From aad893fe69220266de7f78e7345908c3779b6401 Mon Sep 17 00:00:00 2001 From: Evgeniy Alekseev Date: Wed, 10 Mar 2021 01:25:22 +0300 Subject: [PATCH] smart remove function and use built-in packages() function everywhere --- src/ahriman/application/application.py | 9 ++-- src/ahriman/core/build_tools/task.py | 8 ++-- src/ahriman/core/repo/repo_wrapper.py | 11 +++-- src/ahriman/core/report/html.py | 2 +- src/ahriman/core/repository.py | 62 +++++++++++--------------- src/ahriman/models/package.py | 32 ++++++------- 6 files changed, 57 insertions(+), 67 deletions(-) diff --git a/src/ahriman/application/application.py b/src/ahriman/application/application.py index 955e005a..e1b4362b 100644 --- a/src/ahriman/application/application.py +++ b/src/ahriman/application/application.py @@ -44,22 +44,21 @@ class Application: def get_updates(self, no_aur: bool, no_manual: bool, no_vcs: bool, log_fn: Callable[[str], None]) -> List[Package]: updates = [] - checked: List[str] = [] if not no_aur: - updates.extend(self.repository.updates_aur(no_vcs, checked)) + updates.extend(self.repository.updates_aur(no_vcs)) if not no_manual: - updates.extend(self.repository.updates_manual(checked)) + updates.extend(self.repository.updates_manual()) for package in updates: - log_fn(f'{package.name} = {package.version}') + log_fn(f'{package.base} = {package.version}') return updates def add(self, names: List[str]) -> None: def add_manual(name: str) -> None: package = Package.load(name, self.config.get('aur', 'url')) - Task.fetch(os.path.join(self.repository.paths.manual, package.name), package.url) + Task.fetch(os.path.join(self.repository.paths.manual, package.base), package.url) def add_archive(src: str) -> None: dst = os.path.join(self.repository.paths.packages, os.path.basename(src)) diff --git a/src/ahriman/core/build_tools/task.py b/src/ahriman/core/build_tools/task.py index a5e9ee3f..401687da 100644 --- a/src/ahriman/core/build_tools/task.py +++ b/src/ahriman/core/build_tools/task.py @@ -46,7 +46,7 @@ class Task: @property def git_path(self) -> str: - return os.path.join(self.paths.sources, self.package.name) + return os.path.join(self.paths.sources, self.package.base) @staticmethod def fetch(local: str, remote: str) -> None: @@ -58,17 +58,17 @@ class Task: cmd.extend(self.archbuild_flags) cmd.extend(['--'] + self.makechrootpkg_flags) cmd.extend(['--'] + self.makepkg_flags) - self.logger.info(f'using {cmd} for {self.package.name}') + self.logger.info(f'using {cmd} for {self.package.base}') check_output( *cmd, - exception=BuildFailed(self.package.name), + exception=BuildFailed(self.package.base), cwd=self.git_path, logger=self.build_logger) # well it is not actually correct, but we can deal with it return check_output('makepkg', '--packagelist', - exception=BuildFailed(self.package.name), + exception=BuildFailed(self.package.base), cwd=self.git_path).splitlines() def clone(self, path: Optional[str] = None) -> None: diff --git a/src/ahriman/core/repo/repo_wrapper.py b/src/ahriman/core/repo/repo_wrapper.py index 812fc56b..cb9bd05c 100644 --- a/src/ahriman/core/repo/repo_wrapper.py +++ b/src/ahriman/core/repo/repo_wrapper.py @@ -46,13 +46,12 @@ class RepoWrapper: cwd=self.paths.repository, logger=self.logger) - def remove(self, path: str, package: str) -> None: - os.remove(path) - sign_path = f'{path}.sig' - if os.path.exists(sign_path): - os.remove(sign_path) + def remove(self, prefix: str, package: str) -> None: + for fn in filter(lambda f: f.startswith(prefix), os.listdir(self.paths.repository)): + full_path = os.path.join(self.paths.repository, fn) + os.remove(full_path) check_output( 'repo-remove', *self.sign_args, self.repo_path, package, - exception=BuildFailed(path), + exception=BuildFailed(package), cwd=self.paths.repository, logger=self.logger) diff --git a/src/ahriman/core/report/html.py b/src/ahriman/core/report/html.py index 8307f9b3..d9da00bb 100644 --- a/src/ahriman/core/report/html.py +++ b/src/ahriman/core/report/html.py @@ -40,7 +40,7 @@ class HTML(Report): # base template vars if SignSettings.from_option(config.get('sign', 'enabled')) != SignSettings.Disabled: - self.pgp_key = config.get('sign', 'key') + self.pgp_key = config.get('sign', 'key', fallback=None) else: self.pgp_key = None self.homepage = config.get(section, 'homepage', fallback=None) diff --git a/src/ahriman/core/repository.py b/src/ahriman/core/repository.py index 980cb7a6..2756a520 100644 --- a/src/ahriman/core/repository.py +++ b/src/ahriman/core/repository.py @@ -70,9 +70,7 @@ class Repository: full_path = os.path.join(self.paths.repository, fn) try: local = Package.load(full_path, self.aur_url) - if local.name in result: - continue - result[local.name] = local + result.setdefault(local.base, local).packages.update(local.packages) except Exception: self.logger.exception(f'could not load package from {fn}', exc_info=True) continue @@ -91,7 +89,7 @@ class Repository: try: build_single(package) except Exception: - self.logger.exception(f'{package.name} ({self.architecture}) build exception', exc_info=True) + self.logger.exception(f'{package.base} ({self.architecture}) build exception', exc_info=True) continue self._clear_build() @@ -101,19 +99,21 @@ class Repository: ] def process_remove(self, packages: List[str]) -> str: - for fn in os.listdir(self.paths.repository): - if not package_like(fn): - continue - - full_path = os.path.join(self.paths.repository, fn) + def remove_single(package: str) -> None: try: - local = Package.load(full_path, self.aur_url) - if local.name not in packages: - continue - self.wrapper.remove(full_path, local.name) + self.wrapper.remove(package, package) except Exception: - self.logger.exception(f'could not load package from {fn}', exc_info=True) - continue + self.logger.exception(f'could not remove {package}', exc_info=True) + + for local in self.packages(): + if local.base in packages: + to_remove = local.packages + elif local.packages.intersection(packages): + to_remove = local.packages.intersection(packages) + else: + to_remove = set() + for package in to_remove: + remove_single(package) return self.wrapper.repo_path @@ -141,43 +141,33 @@ class Repository: return self.wrapper.repo_path - def updates_aur(self, no_vcs: bool, checked: List[str]) -> List[Package]: + def updates_aur(self, no_vcs: bool) -> List[Package]: result: List[Package] = [] ignore_list = self.config.get_list( self.config.get_section_name('build', self.architecture), 'ignore_packages') - for fn in os.listdir(self.paths.repository): - if not package_like(fn): - continue - - try: - local = Package.load(os.path.join(self.paths.repository, fn), self.aur_url) - remote = Package.load(local.name, self.aur_url) - except Exception: - self.logger.exception(f'could not load package from {fn}', exc_info=True) - continue - if local.name in checked: - continue - if local.name in ignore_list: + for local in self.packages(): + if local.base in ignore_list: continue if local.is_vcs and no_vcs: continue - if local.is_outdated(remote): - result.append(remote) - checked.append(local.name) + try: + remote = Package.load(local.base, self.aur_url) + if local.is_outdated(remote): + result.append(remote) + except Exception: + self.logger.exception(f'could not load remote package {local.base}', exc_info=True) + continue return result - def updates_manual(self, checked: List[str]) -> List[Package]: + def updates_manual(self) -> List[Package]: result: List[Package] = [] for fn in os.listdir(self.paths.manual): local = Package.load(os.path.join(self.paths.manual, fn), self.aur_url) - if local.name in checked: - continue result.append(local) - checked.append(local.name) self._clear_manual() return result \ No newline at end of file diff --git a/src/ahriman/models/package.py b/src/ahriman/models/package.py index 2d59bc66..47aaf7d0 100644 --- a/src/ahriman/models/package.py +++ b/src/ahriman/models/package.py @@ -26,9 +26,9 @@ import os import tempfile from configparser import RawConfigParser -from dataclasses import dataclass +from dataclasses import dataclass, field from srcinfo.parse import parse_srcinfo -from typing import Type +from typing import Set, Type from ahriman.core.exceptions import InvalidPackageInfo from ahriman.core.util import check_output @@ -36,19 +36,19 @@ from ahriman.core.util import check_output @dataclass class Package: - name: str + base: str version: str url: str - remote: bool + packages: Set[str] = field(default_factory=set) @property def is_vcs(self) -> bool: - return self.name.endswith('-bzr') \ - or self.name.endswith('-csv')\ - or self.name.endswith('-darcs')\ - or self.name.endswith('-git')\ - or self.name.endswith('-hg')\ - or self.name.endswith('-svn') + return self.base.endswith('-bzr') \ + or self.base.endswith('-csv')\ + or self.base.endswith('-darcs')\ + or self.base.endswith('-git')\ + or self.base.endswith('-hg')\ + or self.base.endswith('-svn') # additional method to handle vcs versions def actual_version(self) -> str: @@ -74,13 +74,14 @@ class Package: @classmethod def from_archive(cls: Type[Package], path: str, aur_url: str) -> Package: - name, version = check_output('expac', '-p', '%e %v', path, exception=None).split() - return cls(name, version, f'{aur_url}/{name}.git', False) + package, base, version = check_output('expac', '-p', '%n %e %v', path, exception=None).split() + return cls(base, version, f'{aur_url}/{base}.git', packages={package}) @classmethod def from_aur(cls: Type[Package], name: str, aur_url: str)-> Package: package = aur.info(name) - return cls(package.package_base, package.version, f'{aur_url}/{package.package_base}.git', True) + return cls(package.package_base, package.version, f'{aur_url}/{package.package_base}.git', + packages={package.name}) @classmethod def from_build(cls: Type[Package], path: str) -> Package: @@ -91,9 +92,10 @@ class Package: src_info, errors = parse_srcinfo(fn.read()) if errors: raise InvalidPackageInfo(errors) + packages = set(src_info['packages'].keys()) return cls(src_info['pkgbase'], f'{src_info["pkgver"]}-{src_info["pkgrel"]}', - git_config.get('remote "origin"', 'url'), False) + git_config.get('remote "origin"', 'url'), packages-packages) @classmethod def load(cls: Type[Package], path: str, aur_url: str) -> Package: @@ -113,4 +115,4 @@ class Package: def is_outdated(self, remote: Package) -> bool: remote_version = remote.actual_version() # either normal version or updated VCS result = check_output('vercmp', self.version, remote_version, exception=None) - return True if int(result) < 0 else False \ No newline at end of file + return True if int(result) < 0 else False