diff --git a/CHANGELOG.md b/CHANGELOG.md index f0366ef4..abdb8496 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Improvements - Arch - not rechecking sub-dependencies of an AUR dependency to be installed + - allowing AUR packages to be installed as dependencies of a repository package ### Fixes - General @@ -17,6 +18,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Arch - not upgrading a package when a dependent package relies on a specific version with epoch (e.g: alsa-plugins 1:1.2.6-1 would not be upgraded to 1:1.2.6-2 because lib32-alsa-plugins relies on 1:1.2.6) - not informing all the provided packages on the transaction context to the dependency sorting algorithm (could lead to a wrong installation order) + - not displaying all possible AUR providers for a given dependency ### UI - new logo by [DN-debug](https://github.com/DN-debug) diff --git a/bauh/gems/arch/aur.py b/bauh/gems/arch/aur.py index 5716f346..e5054e45 100644 --- a/bauh/gems/arch/aur.py +++ b/bauh/gems/arch/aur.py @@ -2,7 +2,7 @@ import logging import os import re import urllib.parse -from typing import Set, List, Iterable, Dict, Optional +from typing import Set, List, Iterable, Dict, Optional, Generator, Tuple import requests @@ -119,6 +119,43 @@ class AURClient: except: return [] + def map_provided(self, pkgname: str, pkgver: str, provided: Optional[Iterable[str]] = None, strip_epoch: bool = True) -> Set[str]: + all_provided = {pkgname, f"{pkgname}={pkgver.split('-')[0] if strip_epoch else pkgver}"} + + if provided: + for provided in provided: + all_provided.add(provided) + all_provided.add(provided.split('=', 1)[0]) + + return all_provided + + def gen_updates_data(self, names: Iterable[str]) -> Generator[Tuple[str, dict], None, None]: + for package in self.get_info(names): + pkgname, pkgver = package['Name'], package['Version'].split('-')[0] + + deps = set() + + for dtype in ('Depends', 'MakeDepends', 'CheckDepends'): + dep_set = package.get(dtype) + if dep_set: + deps.update(dep_set) + + conflicts = set() + pkg_conflicts = package.get('Conflicts') + + if pkg_conflicts: + conflicts.update(pkg_conflicts) + + yield pkgname, { + 'v': pkgver, + 'b': package.get('PackageBase', pkgname), + 'r': 'aur', + 'p': self.map_provided(pkgname=pkgname, pkgver=pkgver, provided=package.get('Provides'), strip_epoch=False), + 'd': deps, + 'c': conflicts, + 'ds': None, + 's': None} + def get_src_info(self, name: str, real_name: Optional[str] = None) -> dict: srcinfo = self.srcinfo_cache.get(name) @@ -229,7 +266,7 @@ class AURClient: def clean_caches(self): self.srcinfo_cache.clear() - def map_update_data(self, pkgname: str, latest_version: Optional[str], srcinfo: Optional[dict] = None) -> dict: + def map_update_data(self, pkgname: str, latest_version: Optional[str] = None, srcinfo: Optional[dict] = None) -> dict: info = self.get_src_info(pkgname) if not srcinfo else srcinfo provided = set() diff --git a/bauh/gems/arch/controller.py b/bauh/gems/arch/controller.py index b41fb0b1..f3783467 100644 --- a/bauh/gems/arch/controller.py +++ b/bauh/gems/arch/controller.py @@ -209,7 +209,7 @@ class ArchManager(SoftwareManager): self.enabled = True self.arch_distro = context.distro == 'arch' self.categories = {} - self.deps_analyser = DependenciesAnalyser(self.aur_client, self.i18n) + self.deps_analyser = DependenciesAnalyser(self.aur_client, self.i18n, self.logger) self.http_client = context.http_client self._custom_actions: Optional[Dict[str, CustomSoftwareAction]] = None self.index_aur = None @@ -2333,7 +2333,7 @@ class ArchManager(SoftwareManager): to_install = [] if context.missing_deps: - to_install.extend((d[0] for d in context.missing_deps)) + to_install.extend((d[0] for d in context.missing_deps if d[1] != 'aur')) to_install.extend(pkgpaths) @@ -2357,7 +2357,8 @@ class ArchManager(SoftwareManager): status_handler = None installed_with_same_name = self.read_installed(disk_loader=context.disk_loader, internet_available=True, names=context.get_package_names()).installed - context.watcher.change_substatus(self.i18n['arch.installing.package'].format(bold(context.name))) + context.watcher.change_substatus(self.i18n['arch.installing.package'].format(bold(context.name))) # + installed = self._handle_install_call(context=context, to_install=to_install, status_handler=status_handler) if status_handler: @@ -2600,29 +2601,9 @@ class ArchManager(SoftwareManager): return TransactionResult(success=pkg_installed, installed=installed, removed=removed) def _install_from_repository(self, context: TransactionContext) -> bool: - try: - missing_deps = self._list_missing_deps(context) - except PackageNotFoundException: - self.logger.error("Package '{}' was not found") + if not self._handle_missing_deps(context): return False - if missing_deps is None: - return False # called off by the user - - if missing_deps: - if any((dep for dep in missing_deps if dep[1] == 'aur')): - context.watcher.show_message(title=self.i18n['error'].capitalize(), - body=self.i18n['arch.install.repo_pkg.error.aur_deps'], - type_=MessageType.ERROR) - return False - - context.missing_deps = missing_deps - context.watcher.change_substatus(self.i18n['arch.missing_deps_found'].format(bold(context.name))) - - if not confirmation.request_install_missing_deps(context.name, missing_deps, context.watcher, self.i18n): - context.watcher.print(self.i18n['action.cancelled']) - return False - res = self._install(context) if res and not context.skip_opt_deps: diff --git a/bauh/gems/arch/dependencies.py b/bauh/gems/arch/dependencies.py index a8af0530..5246edc8 100644 --- a/bauh/gems/arch/dependencies.py +++ b/bauh/gems/arch/dependencies.py @@ -1,7 +1,8 @@ import re import traceback +from logging import Logger from threading import Thread -from typing import Set, List, Tuple, Dict, Iterable, Optional +from typing import Set, List, Tuple, Dict, Iterable, Optional, Generator from bauh.api.abstract.handler import ProcessWatcher from bauh.gems.arch import pacman, message, sorting, confirmation @@ -13,10 +14,11 @@ from bauh.view.util.translation import I18n class DependenciesAnalyser: - def __init__(self, aur_client: AURClient, i18n: I18n): + def __init__(self, aur_client: AURClient, i18n: I18n, logger: Logger): self.aur_client = aur_client self.i18n = i18n self.re_dep_operator = re.compile(r'([<>=]+)') + self._log = logger def _fill_repository(self, name: str, output: List[Tuple[str, str]]): @@ -40,8 +42,8 @@ class DependenciesAnalyser: output.append((name, '')) - def get_missing_packages(self, names: Set[str], repository: str = None, in_analysis: Set[str] = None) -> List[ - Tuple[str, str]]: + def get_missing_packages(self, names: Set[str], repository: Optional[str] = None, in_analysis: Optional[Set[str]] = None) -> \ + List[Tuple[str, str]]: """ :param names: :param repository: @@ -157,7 +159,8 @@ class DependenciesAnalyser: if missing_subdeps: for dep in missing_subdeps: if not dep[1]: - message.show_dep_not_found(dep[0], self.i18n, watcher) + dependents = ', '.join(deps[0]) # it is not possible to know which is the exact dependent + message.show_dep_not_found(dep[0], self.i18n, watcher, dependent=dependents) return for dep in missing_subdeps: @@ -175,25 +178,28 @@ class DependenciesAnalyser: return sorted_deps - def _fill_missing_dep(self, dep_name: str, dep_exp: str, aur_index: Iterable[str], - missing_deps: Set[Tuple[str, str]], - remote_provided_map: Dict[str, Set[str]], remote_repo_map: Dict[str, str], - repo_deps: Set[str], aur_deps: Set[str], deps_data: Dict[str, dict], watcher: ProcessWatcher, - automatch_providers: bool): - + def _find_repo_providers(self, dep_name: str, dep_exp: str, remote_provided_map: Dict[str, Set[str]], + deps_data: Dict[str, dict], remote_repo_map: Dict[str, str]) -> Generator[Tuple[str, str, Optional[dict]], None, None]: if dep_name == dep_exp: providers = remote_provided_map.get(dep_name) - if not providers: # try to find the package through the pacman's search mechanism + if providers: + for pkgname in providers: + yield pkgname, remote_repo_map.get(pkgname), None + + else: # try to find the package through the pacman's search mechanism match = pacman.find_one_match(dep_name) if match: - providers = {match} + yield match, remote_repo_map.get(match), None else: # handling cases when the dep has an expression ( e.g: xpto>=0.12 ) - providers = remote_provided_map.get(dep_exp) + exact_exp_providers = remote_provided_map.get(dep_exp) - if providers is None: + if exact_exp_providers: + for p in exact_exp_providers: + yield p, remote_repo_map.get(p), None + else: providers = remote_provided_map.get(dep_name) if not providers: # try to find the package through the pacman's search mechanism @@ -203,103 +209,177 @@ class DependenciesAnalyser: providers = {match} if providers: - no_mapped_data = {p for p in providers if - p not in deps_data} # checking providers with no mapped data + providers_no_provided_data = {p for p in providers if p not in deps_data} + missing_providers_data = None - if no_mapped_data: - providers_data = pacman.map_updates_data(no_mapped_data) + if providers_no_provided_data: + missing_providers_data = pacman.map_updates_data(providers_no_provided_data) - if not providers_data: - raise Exception("Could not retrieve the info from providers: {}".format(no_mapped_data)) + if not missing_providers_data: + raise Exception(f"Could not retrieve information from providers: " + f"{', '.join(providers_no_provided_data)}") - deps_data.update(providers_data) # adding missing providers data + data_not_found = {p for p in providers if p not in missing_providers_data} + + if data_not_found: + raise Exception(f"Could not retrieve information from providers: " + f"{', '.join(data_not_found)}") - matched_providers = set() split_informed_dep = self.re_dep_operator.split(dep_exp) - try: - version_required = split_informed_dep[2] - exp_op = split_informed_dep[1] if split_informed_dep[1] != '=' else '==' - for p in providers: - provided = deps_data[p]['p'] + version_required = split_informed_dep[2] + exp_op = split_informed_dep[1] if split_informed_dep[1] != '=' else '==' - for provided_exp in provided: - split_dep = self.re_dep_operator.split(provided_exp) + for p in providers: + info = deps_data.get(p) - if len(split_dep) == 3 and split_dep[0] == dep_name: - version_provided = split_dep[2] + if not info and missing_providers_data: + info = missing_providers_data[p] - if match_required_version(version_provided, exp_op, version_required): - matched_providers.add(p) - break + for provided_exp in info['p']: + split_dep = self.re_dep_operator.split(provided_exp) - providers = matched_providers - except: - traceback.print_exc() + if len(split_dep) == 3 and split_dep[0] == dep_name: + version_provided = split_dep[2] - if providers: - if len(providers) > 1: - dep_data = None + if match_required_version(version_provided, exp_op, version_required): + yield p, remote_repo_map.get(p), info + break - if automatch_providers: - exact_matches = [p for p in providers if p == dep_name] - - if exact_matches: - dep_data = (exact_matches[0], remote_repo_map.get(exact_matches[0])) - - if not dep_data: - dep_data = (dep_name, '__several__') - else: - real_name = providers.pop() - dep_data = (real_name, remote_repo_map.get(real_name)) - - repo_deps.add(dep_data[0]) - missing_deps.add(dep_data) - - elif aur_index and dep_name in aur_index: + def _find_aur_providers(self, dep_name: str, dep_exp: str, aur_index: Iterable[str], exact_match: bool) -> Generator[Tuple[str, dict], None, None]: + if exact_match and dep_name in aur_index: if dep_name == dep_exp: - aur_deps.add(dep_name) - missing_deps.add((dep_name, 'aur')) + yield from self.aur_client.gen_updates_data((dep_name,)) + return else: - dep_info = self.aur_client.get_info({dep_name}) - - if not dep_info: - self.__raise_dependency_not_found(dep_exp, watcher) - else: - try: - dep_version = dep_info[0]['Version'] - except: - traceback.print_exc() - return self.__raise_dependency_not_found(dep_exp, watcher) - + for _, dep_data in self.aur_client.gen_updates_data((dep_name,)): split_informed_dep = self.re_dep_operator.split(dep_exp) + version_required = split_informed_dep[2] + exp_op = split_informed_dep[1].strip() + + if match_required_version(dep_data['v'], exp_op, version_required): + yield dep_name, dep_data + return + + aur_search = self.aur_client.search(dep_name) + + if aur_search: + if dep_name == dep_exp: + version_required, exp_op = None, None + else: + split_informed_dep = self.re_dep_operator.split(dep_exp) + version_required = split_informed_dep[2] + exp_op = split_informed_dep[1] if split_informed_dep[1] != '=' else '==' + + for pkgname, pkgdata in self.aur_client.gen_updates_data( + (aur_res['Name'] for aur_res in aur_search['results'])): + if pkgname == dep_name or (dep_name in pkgdata['p']): try: - version_required = split_informed_dep[2] - exp_op = split_informed_dep[1].strip() - - if match_required_version(dep_version, exp_op, version_required): - aur_deps.add(dep_name) - missing_deps.add((dep_name, 'aur')) + if not version_required or match_required_version(pkgdata['v'], exp_op, + version_required): + yield pkgname, pkgdata except: - self.__raise_dependency_not_found(dep_exp, watcher) - else: - self.__raise_dependency_not_found(dep_exp, watcher) + self._log.warning(f"Could not compare AUR package '{pkgname}' version '{pkgdata['v']}' " + f"with the dependency expression '{dep_exp}'") + traceback.print_exc() - def __raise_dependency_not_found(self, dep_exp: str, watcher: Optional[ProcessWatcher]): + def _fill_missing_dep(self, dep_name: str, dep_exp: str, aur_index: Iterable[str], + missing_deps: Set[Tuple[str, str]], + remote_provided_map: Dict[str, Set[str]], remote_repo_map: Dict[str, str], + repo_deps: Set[str], aur_deps: Set[str], deps_data: Dict[str, dict], watcher: ProcessWatcher, + automatch_providers: bool, dependent: Optional[str] = None): + + repo_matches = None + + for pkgname, repo, data in self._find_repo_providers(dep_name=dep_name, dep_exp=dep_exp, + remote_repo_map=remote_repo_map, + remote_provided_map=remote_provided_map, + deps_data=deps_data): + if automatch_providers and pkgname == dep_name: + missing_deps.add((pkgname, repo)) + repo_deps.add(pkgname) + + if data: + deps_data[pkgname] = data + + return + + if repo_matches is None: + repo_matches = [] + + repo_matches.append((pkgname, repo, data)) + + aur_matches = None + + if aur_index: + for pkgname, pkgdata in self._find_aur_providers(dep_name=dep_name, dep_exp=dep_exp, aur_index=aur_index, + exact_match=automatch_providers): + if automatch_providers and pkgname == dep_name: + missing_deps.add((pkgname, 'aur')) + aur_deps.add(pkgname) + deps_data[pkgname] = pkgdata + return + + if aur_matches is None: + aur_matches = [] + + aur_matches.append((pkgname, pkgdata)) + + total_matches = (len(repo_matches) if repo_matches else 0) + (len(aur_matches) if aur_matches else 0) + + if total_matches == 0: + self.__raise_dependency_not_found(dep_exp, watcher, dependent) + elif total_matches == 1: + if repo_matches: + repo_pkg = [*repo_matches][0] + + if repo_pkg[2]: + deps_data[repo_pkg[0]] = repo_pkg[2] # already updating the deps data (if available) + + match = (repo_pkg[0], repo_pkg[1]) + repo_deps.add(repo_pkg[0]) + else: + aur_pkg = aur_matches[0] + deps_data[aur_pkg[0]] = aur_pkg[1] # already updating the deps data (if available) + aur_deps.add(aur_pkg[0]) + match = aur_pkg[0], 'aur' + + missing_deps.add(match) + + elif total_matches > 1: + missing_deps.add((dep_name, '__several__')) + + if repo_matches: + repo_deps.add(dep_name) + + if aur_matches: + aur_deps.add(dep_name) + + for pkgname, _ in aur_matches: + for key in (dep_name, dep_exp): + key_provided = remote_provided_map.get(key, set()) + remote_provided_map[key] = key_provided + key_provided.add(pkgname) + + if pkgname not in remote_repo_map: + remote_repo_map[pkgname] = 'aur' + + def __raise_dependency_not_found(self, dep_exp: str, watcher: Optional[ProcessWatcher], dependent: Optional[str] = None): if watcher: - message.show_dep_not_found(dep_exp, self.i18n, watcher) + message.show_dep_not_found(depname=dep_exp, i18n=self.i18n, watcher=watcher, dependent=dependent) raise PackageNotFoundException(dep_exp) else: raise PackageNotFoundException(dep_exp) - def __fill_aur_update_data(self, pkgname: str, output: dict): - output[pkgname] = self.aur_client.map_update_data(pkgname, None) + def _fill_aur_updates_data(self, pkgnames: Iterable[str], output_data: dict): + for pkgname, pkgdata in self.aur_client.gen_updates_data(pkgnames): + output_data[pkgname] = pkgdata def map_missing_deps(self, pkgs_data: Dict[str, dict], provided_map: Dict[str, Set[str]], remote_provided_map: Dict[str, Set[str]], remote_repo_map: Dict[str, str], aur_index: Iterable[str], deps_checked: Set[str], deps_data: Dict[str, dict], sort: bool, watcher: ProcessWatcher, choose_providers: bool = True, - automatch_providers: bool = False) -> List[Tuple[str, str]]: + automatch_providers: bool = False) -> Optional[List[Tuple[str, str]]]: sorted_deps = [] # it will hold the proper order to install the missing dependencies missing_deps, repo_missing, aur_missing = set(), set(), set() @@ -325,7 +405,8 @@ class DependenciesAnalyser: remote_repo_map=remote_repo_map, repo_deps=repo_missing, aur_deps=aur_missing, watcher=watcher, deps_data=deps_data, - automatch_providers=automatch_providers) + automatch_providers=automatch_providers, + dependent=p) else: version_pattern = '{}='.format(dep_name) version_found = [p for p in provided_map if p.startswith(version_pattern)] @@ -343,7 +424,8 @@ class DependenciesAnalyser: repo_deps=repo_missing, aur_deps=aur_missing, watcher=watcher, deps_data=deps_data, - automatch_providers=automatch_providers) + automatch_providers=automatch_providers, + dependent=p) else: self._fill_missing_dep(dep_name=dep_name, dep_exp=dep, aur_index=aur_index, missing_deps=missing_deps, @@ -352,34 +434,11 @@ class DependenciesAnalyser: repo_deps=repo_missing, aur_deps=aur_missing, watcher=watcher, deps_data=deps_data, - automatch_providers=automatch_providers) + automatch_providers=automatch_providers, + dependent=p) if missing_deps: - if repo_missing: - with_single_providers = [] - - for d in missing_deps: - if d[0] in repo_missing and d[0] not in deps_data: - if d[1] == '__several__': - deps_data[d[0]] = {'d': None, 'p': d[0], 'r': d[1]} - else: - with_single_providers.append(d[0]) - - if with_single_providers: - data = pacman.map_updates_data(with_single_providers) - - if data: - deps_data.update(data) - - if aur_missing: - aur_threads = [] - for pkgname in aur_missing: - t = Thread(target=self.__fill_aur_update_data, args=(pkgname, deps_data), daemon=True) - t.start() - aur_threads.append(t) - - for t in aur_threads: - t.join() + self._fill_single_providers_data(missing_deps, repo_missing, aur_missing, deps_data) missing_subdeps = self.map_missing_deps(pkgs_data={**deps_data}, provided_map=provided_map, aur_index=aur_index, deps_checked=deps_checked, sort=False, deps_data=deps_data, @@ -406,6 +465,51 @@ class DependenciesAnalyser: return sorted_deps + def _fill_single_providers_data(self, all_missing_deps: Iterable[Tuple[str, str]], repo_missing_deps: Iterable[str], aur_missing_deps: Iterable[str], deps_data: Dict[str, dict]): + """ + fills the missing data of the single dependency providers since they are already considered dependencies + (when several providers are available for given a dependency, the user must choose first) + """ + repo_providers_no_data, aur_providers_no_data = None, None + + for dep_name, dep_repo in all_missing_deps: + if dep_repo == '__several__': + deps_data[dep_name] = {'d': None, 'p': {dep_name}, 'r': dep_repo} + elif dep_name not in deps_data: + if repo_missing_deps and dep_name in repo_missing_deps: + if repo_providers_no_data is None: + repo_providers_no_data = set() + + repo_providers_no_data.add(dep_name) + elif aur_missing_deps and dep_name in aur_missing_deps: + if aur_providers_no_data is None: + aur_providers_no_data = set() + + aur_providers_no_data.add(dep_name) + + aur_data_filler, aur_providers_data = None, None + + if aur_providers_no_data: + aur_providers_data = dict() + aur_data_filler = Thread(target=self._fill_aur_updates_data, + args=(aur_providers_no_data, aur_providers_data)) + aur_data_filler.start() + + if repo_providers_no_data: + repo_providers_data = pacman.map_updates_data(repo_providers_no_data) + + if repo_providers_data: + deps_data.update(repo_providers_data) + + for pkgname, pkgdata in self.aur_client.gen_updates_data(aur_providers_no_data): + deps_data[pkgname] = pkgdata + + if aur_data_filler: + aur_data_filler.join() + + if aur_providers_data: + deps_data.update(aur_providers_data) + def fill_providers_deps(self, missing_deps: List[Tuple[str, str]], provided_map: Dict[str, Set[str]], remote_repo_map: Dict[str, str], already_checked: Set[str], remote_provided_map: Dict[str, Set[str]], @@ -429,21 +533,45 @@ class DependenciesAnalyser: remote_provided_map) if deps_providers: - all_providers = set() + providers_repos = {} + repos_providers = set() for providers in deps_providers.values(): - all_providers.update(providers) + for provider in providers: + if remote_repo_map.get(provider) == 'aur': + providers_repos[provider] = 'aur' + else: + repos_providers.add(provider) - providers_repos = pacman.map_repositories(all_providers) + providers_repos.update(pacman.map_repositories(repos_providers)) selected_providers = confirmation.request_providers(deps_providers, providers_repos, watcher, self.i18n) if not selected_providers: return else: - providers_data = pacman.map_updates_data( - selected_providers) # adding the chosen providers to re-check the missing deps - provided_map.update(pacman.map_provided(remote=True, - pkgs=selected_providers)) # adding the providers as "installed" packages + # adding the chosen providers for re-checking the missing dependencies + repo_selected, aur_selected = set(), set() + + for provider in selected_providers: + if provider in repos_providers: + repo_selected.add(provider) + else: + aur_selected.add(provider) + + providers_data = dict() + + if repo_selected: + providers_data.update(pacman.map_updates_data(repo_selected)) + # adding the providers as "installed" packages + provided_map.update(pacman.map_provided(remote=True, pkgs=repo_selected)) + + if aur_selected: + for pkgname, pkgdata in self.aur_client.gen_updates_data(aur_selected): + providers_data[pkgname] = pkgdata + for provider in pkgdata['p']: # adding the providers as "installed" packages + currently_provided = provided_map.get(provider, set()) + provided_map[provider] = currently_provided + currently_provided.add(pkgname) providers_deps = self.map_missing_deps(pkgs_data=providers_data, provided_map=provided_map, @@ -457,6 +585,9 @@ class DependenciesAnalyser: choose_providers=True, automatch_providers=automatch_providers) + if providers_deps is None: # it means the user called off the installation process + return + # cleaning the already mapped providers deps: to_remove = [] diff --git a/bauh/gems/arch/message.py b/bauh/gems/arch/message.py index d3127b40..1a43fbac 100644 --- a/bauh/gems/arch/message.py +++ b/bauh/gems/arch/message.py @@ -1,4 +1,4 @@ -from typing import Iterable +from typing import Iterable, Optional from bauh.api.abstract.handler import ProcessWatcher from bauh.api.abstract.view import MessageType @@ -13,11 +13,13 @@ def show_deps_not_installed(watcher: ProcessWatcher, pkgname: str, depnames: Ite type_=MessageType.ERROR) -def show_dep_not_found(depname: str, i18n: I18n, watcher: ProcessWatcher): +def show_dep_not_found(depname: str, i18n: I18n, watcher: ProcessWatcher, dependent: Optional[str] = None): - body = '

{}

{}

{}

'.format(i18n['arch.install.dep_not_found.body.l1'].format(bold(depname)), - i18n['arch.install.dep_not_found.body.l2'], - i18n['arch.install.dep_not_found.body.l3']) + source = f" {bold('(' + dependent + ')')}" if dependent else '' + + body = f"

{i18n['arch.install.dep_not_found.body.l1'].format(dep=bold(depname), source=source)}

" \ + f"

<{i18n['arch.install.dep_not_found.body.l2']}

" \ + f"

{i18n['arch.install.dep_not_found.body.l3']}

" watcher.show_message(title=i18n['arch.install.dep_not_found.title'].capitalize(), body=body, diff --git a/bauh/gems/arch/resources/locale/ca b/bauh/gems/arch/resources/locale/ca index ec8381d5..d7559f45 100644 --- a/bauh/gems/arch/resources/locale/ca +++ b/bauh/gems/arch/resources/locale/ca @@ -195,7 +195,7 @@ arch.install.aur.unknown_key.title=Clau pública necessària arch.install.aur.unknown_key.body=Per a continuar amb la instal·lació de {} cal confiar en la clau pública següent {} arch.install.conflict.popup.body=Les aplicacions {} estan en conflicte. Heu de desinstal·lar una per a instal·lar l’altra. Voleu continuar? arch.install.conflict.popup.title=S’ha detectat un conflicte -arch.install.dep_not_found.body.l1=No s’ha trobat la dependència requerida {} a l’AUR ni als dipòsits +arch.install.dep_not_found.body.l1=No s’ha trobat la dependència requerida {dep}{source} a l’AUR ni als dipòsits arch.install.dep_not_found.body.l2=It might be a package database synchronization problem. arch.install.dep_not_found.body.l3=Operation cancelled. arch.install.dep_not_found.title=No s’ha trobat la dependència @@ -208,7 +208,6 @@ arch.install.optdep.error=Could not install the optional packages: {} arch.install.optdeps.request.body={} s’ha instal·lat correctament. Hi ha paquets opcionals associats que potser voldreu instal·lar arch.install.optdeps.request.help=Marqueu els que voleu arch.install.optdeps.request.title=Dependències opcionals -arch.install.repo_pkg.error.aur_deps=It is not possible to install an AUR package as dependency of a repository package arch.installing.package=S’està instal·lant el paquet {} arch.checking_unnecessary_deps=Checking if there are packages no longer needed arch.makepkg.optimizing=Optimitzant la recopilació diff --git a/bauh/gems/arch/resources/locale/de b/bauh/gems/arch/resources/locale/de index f46459cc..9b4ec6fe 100644 --- a/bauh/gems/arch/resources/locale/de +++ b/bauh/gems/arch/resources/locale/de @@ -195,7 +195,7 @@ arch.install.aur.unknown_key.body=Um mit der Installation von {} fortzufahren is arch.install.aur.unknown_key.title=Öffentlicher Schlüssel nötig arch.install.conflict.popup.body=Die Anwendungen {} können nicht gleichzeitig installiert sein. Du musst eine deinstallieren um die andere zu installieren. Fortfahren? arch.install.conflict.popup.title=Konflikt entdeckt -arch.install.dep_not_found.body.l1=Nötige Abhängigkeit {} wurde weder im AUR noch in den standard Spiegelservern gefunden +arch.install.dep_not_found.body.l1=Nötige Abhängigkeit {dep}{source} wurde weder im AUR noch in den standard Spiegelservern gefunden arch.install.dep_not_found.body.l2=It might be a package database synchronization problem. arch.install.dep_not_found.body.l3=Operation cancelled. arch.install.dep_not_found.title=Abhängigkeit nicht gefunden @@ -208,7 +208,6 @@ arch.install.optdep.error=Could not install the optional packages: {} arch.install.optdeps.request.body={} wurde erfolgreich installiert! Es gibt optionale zugehörige Pakete welche du vielleicht auch installieren möchtest arch.install.optdeps.request.help=Wähle entsprechende aus arch.install.optdeps.request.title=Optionale Abhängigkeiten -arch.install.repo_pkg.error.aur_deps=It is not possible to install an AUR package as dependency of a repository package arch.installing.package=Paket {} installieren arch.checking_unnecessary_deps=Checking if there are packages no longer needed arch.makepkg.optimizing=Optimiert die Zusammenstellung diff --git a/bauh/gems/arch/resources/locale/en b/bauh/gems/arch/resources/locale/en index a3137e06..2cadd739 100644 --- a/bauh/gems/arch/resources/locale/en +++ b/bauh/gems/arch/resources/locale/en @@ -195,7 +195,7 @@ arch.install.aur.unknown_key.body=To continue {} installation is necessary to tr arch.install.aur.unknown_key.title=Public key required arch.install.conflict.popup.body=The applications {} are in conflict. You must uninstall one to install the other. Continue ? arch.install.conflict.popup.title=Conflict detected -arch.install.dep_not_found.body.l1=Required dependency {} was not found in AUR nor in the repositories. +arch.install.dep_not_found.body.l1=Required dependency {dep}{source} was not found on the repositories nor AUR. arch.install.dep_not_found.body.l2=It might be a package database synchronization problem. arch.install.dep_not_found.body.l3=Operation cancelled. arch.install.dep_not_found.title=Dependency not found @@ -208,7 +208,6 @@ arch.install.optdep.error=Could not install the optional packages: {} arch.install.optdeps.request.body={} was succesfully installed ! There are some optional associated packages that you might want to install arch.install.optdeps.request.help=Check those you want arch.install.optdeps.request.title=Optional dependencies -arch.install.repo_pkg.error.aur_deps=It is not possible to install an AUR package as dependency of a repository package arch.installing.package=Installing {} package arch.checking_unnecessary_deps=Checking if there are packages no longer needed arch.makepkg.optimizing=Optimizing the compilation diff --git a/bauh/gems/arch/resources/locale/es b/bauh/gems/arch/resources/locale/es index 951cf926..e7dd9575 100644 --- a/bauh/gems/arch/resources/locale/es +++ b/bauh/gems/arch/resources/locale/es @@ -195,7 +195,7 @@ arch.install.aur.unknown_key.body=Para continuar la instalación de {} es necesa arch.install.aur.unknown_key.title=Clave pública necesaria arch.install.conflict.popup.body=Los aplicativos {} estan en conflicto. Debe desinstalar uno para instalar el otro. ¿Continuar? arch.install.conflict.popup.title=Conflicto detectado -arch.install.dep_not_found.body.l1=No se encontró la dependencia requerida {} en AUR ni en los repositorios. +arch.install.dep_not_found.body.l1=No se encontró la dependencia requerida {dep}{source} en AUR ni en los repositorios. arch.install.dep_not_found.body.l2=Puede ser un problema de sincronización de la base de paquetes. arch.install.dep_not_found.body.l3=Operación cancelada. arch.install.dep_not_found.title=Dependencia no encontrada @@ -208,7 +208,6 @@ arch.install.optdep.error=No se pudo instalar los paquetes opcionales: {} arch.install.optdeps.request.body=¡{} se instaló correctamente! Hay algunos paquetes opcionales asociados que es posible que desee instalar arch.install.optdeps.request.help=Marque los que desee arch.install.optdeps.request.title=Dependencias opcionales -arch.install.repo_pkg.error.aur_deps=It is not possible to install an AUR package as dependency of a repository package arch.installing.package=Instalando el paquete {} arch.checking_unnecessary_deps=Verificando se hay paquetes innecesarios arch.makepkg.optimizing=Optimizing the compilation diff --git a/bauh/gems/arch/resources/locale/fr b/bauh/gems/arch/resources/locale/fr index b7fe4b39..d62bf653 100644 --- a/bauh/gems/arch/resources/locale/fr +++ b/bauh/gems/arch/resources/locale/fr @@ -195,7 +195,7 @@ arch.install.aur.unknown_key.body=Pour continuer à installer {} il faut faire c arch.install.aur.unknown_key.title=Clé publique requise arch.install.conflict.popup.body=Les applications {} sont en conflit. Il faut en désinstaller une pour installer l'autre. Continuer ? arch.install.conflict.popup.title=Conflit détecté -arch.install.dep_not_found.body.l1=Dépendance requise {} absente d AUR ou des dépôts. +arch.install.dep_not_found.body.l1=Dépendance requise {dep}{source} absente d AUR ou des dépôts. arch.install.dep_not_found.body.l2=Sans doute un problème de synchronisation de base de données. arch.install.dep_not_found.body.l3=Operation annulée. arch.install.dep_not_found.title=Dependance non trouvée @@ -208,7 +208,6 @@ arch.install.optdep.error=Impossible d'installer les paquets optionnels: {} arch.install.optdeps.request.body={} installé avec succès ! Il y a des paquets optionnels que vous pouvez installer arch.install.optdeps.request.help=Cochez ceux que vous désirez arch.install.optdeps.request.title=Dépendances optionnelles -arch.install.repo_pkg.error.aur_deps=Impossible d'installer un paquet AUR comme une dépendance d'un paquet venant d'un dépôt arch.installing.package=Installation du paquet {} arch.checking_unnecessary_deps=Calcul des paquets devenus inutiles arch.makepkg.optimizing=Optimisation de la compilation diff --git a/bauh/gems/arch/resources/locale/it b/bauh/gems/arch/resources/locale/it index eb106094..65a626e3 100644 --- a/bauh/gems/arch/resources/locale/it +++ b/bauh/gems/arch/resources/locale/it @@ -195,7 +195,7 @@ arch.install.aur.unknown_key.body=Per continuare {} l'installazione è necessari arch.install.aur.unknown_key.title=Chiave pubblica richiesta arch.install.conflict.popup.body=Le applicazioni {} sono in conflitto. È necessario disinstallarne una per installare l'altra. Continua ? arch.install.conflict.popup.title=Conflitto rilevato -arch.install.dep_not_found.body.l1=La dipendenza richiesta {} non è stata trovata in AUR né nei depositos. +arch.install.dep_not_found.body.l1=La dipendenza richiesta {dep}{source} non è stata trovata in AUR né nei depositos. arch.install.dep_not_found.body.l2=It might be a package database synchronization problem. arch.install.dep_not_found.body.l3=Operation cancelled. arch.install.dep_not_found.title=Dipendenza non trovata @@ -208,7 +208,6 @@ arch.install.optdep.error=Could not install the optional packages: {} arch.install.optdeps.request.body={} è stato installato con successo! Ci sono alcuni pacchetti associati opzionali che potresti voler installare arch.install.optdeps.request.help=Controlla quelli che vuoi arch.install.optdeps.request.title=Dipendenze opzionali -arch.install.repo_pkg.error.aur_deps=It is not possible to install an AUR package as dependency of a repository package arch.installing.package=Installazione del pacchetto {} arch.checking_unnecessary_deps=Checking if there are packages no longer needed arch.makepkg.optimizing=Ottimizzando la compilazione diff --git a/bauh/gems/arch/resources/locale/pt b/bauh/gems/arch/resources/locale/pt index da9a8c5d..d726da10 100644 --- a/bauh/gems/arch/resources/locale/pt +++ b/bauh/gems/arch/resources/locale/pt @@ -194,7 +194,7 @@ arch.install.aur.unknown_key.body=Para continuar a instalação de {} é ncessá arch.install.aur.unknown_key.title=Chave pública necessária arch.install.conflict.popup.body=Os aplicativos {} estão em conflito. Você precisa desinstalar um para instalar o outro. Continuar ? arch.install.conflict.popup.title=Conflito detectado -arch.install.dep_not_found.body.l1=A dependência {} não foi encontrado no AUR nem nos repositórios. +arch.install.dep_not_found.body.l1=A dependência {dep}{source} não foi encontrado no AUR nem nos repositórios. arch.install.dep_not_found.body.l2=Pode ser um problema de sincronização das bases de pacotes. arch.install.dep_not_found.body.l3=Operação cancelada. arch.install.dep_not_found.title=Dependência não encontrada @@ -207,7 +207,6 @@ arch.install.optdep.error=Não foi possível instalar os pacotes opcionais: {} arch.install.optdeps.request.body={} foi instalado com sucesso ! Existem alguns pacotes opcionais associados que você talvez queira instalar arch.install.optdeps.request.help=Marque os desejados arch.install.optdeps.request.title=Dependências opcionais -arch.install.repo_pkg.error.aur_deps=Não é possível instalar um pacote do AUR como dependência de um pacote de repositório arch.installing.package=Instalando o pacote {} arch.checking_unnecessary_deps=Verificando se há pacotes não mais necessários arch.makepkg.optimizing=Otimizando a compilação diff --git a/bauh/gems/arch/resources/locale/ru b/bauh/gems/arch/resources/locale/ru index 107fb6bc..dce0327f 100644 --- a/bauh/gems/arch/resources/locale/ru +++ b/bauh/gems/arch/resources/locale/ru @@ -195,7 +195,7 @@ arch.install.aur.unknown_key.body=Для продолжения установк arch.install.aur.unknown_key.title=Требуется открытый ключ arch.install.conflict.popup.body=Приложения {} находятся в конфликте. Вы должны удалить одно, чтобы установить другоое. Продолжить ? arch.install.conflict.popup.title=Обнаружен конфликт -arch.install.dep_not_found.body.l1=Требуемая зависимость {} не была найдена ни в AUR, ни в зеркалах по умолчанию. +arch.install.dep_not_found.body.l1=Требуемая зависимость {dep}{source} не была найдена ни в AUR, ни в зеркалах по умолчанию. arch.install.dep_not_found.body.l2=It might be a package database synchronization problem. arch.install.dep_not_found.body.l3=Operation cancelled. arch.install.dep_not_found.title=Зависимость не найдена @@ -208,7 +208,6 @@ arch.install.optdep.error=Could not install the optional packages: {} arch.install.optdeps.request.body={} успешно установлен ! Есть некоторые дополнительные связанные пакеты, которые вы можете установить arch.install.optdeps.request.help=Отметьте те, которые вы хотите установить arch.install.optdeps.request.title=Необязательные зависимости -arch.install.repo_pkg.error.aur_deps=It is not possible to install an AUR package as dependency of a repository package arch.installing.package=Установка пакета {} arch.checking_unnecessary_deps=Checking if there are packages no longer needed arch.makepkg.optimizing=Оптимизация компиляции diff --git a/bauh/gems/arch/resources/locale/tr b/bauh/gems/arch/resources/locale/tr index a6520a28..01f75d91 100644 --- a/bauh/gems/arch/resources/locale/tr +++ b/bauh/gems/arch/resources/locale/tr @@ -195,7 +195,7 @@ arch.install.aur.unknown_key.body=Yüklemeye devam etmek için {} aşağıdaki o arch.install.aur.unknown_key.title=Ortak anahtar gerekli arch.install.conflict.popup.body={} Uygulamaları çakışıyor. Diğerini kurmak için birini kaldırmalısınız. Devam et ? arch.install.conflict.popup.title=Çakışma tespit edildi -arch.install.dep_not_found.body.l1=Gerekli bağımlılık {} ne AUR ne de resmi depolarda bulunamadı. +arch.install.dep_not_found.body.l1=Gerekli bağımlılık {dep}{source} ne AUR ne de resmi depolarda bulunamadı. arch.install.dep_not_found.body.l2=Bir paket veritabanı senkronizasyon sorunu olabilir. arch.install.dep_not_found.body.l3=Operation cancelled. arch.install.dep_not_found.title=Bağımlılık bulunamadı @@ -208,7 +208,6 @@ arch.install.optdep.error=Tercihe bağlı paketler yüklenemedi: {} arch.install.optdeps.request.body={} başarıyla yüklendi! Yüklemek isteyebileceğiniz bazı tercihe bağlı bağımlılıklar vardır arch.install.optdeps.request.help=İstediklerinizi kontrol edin arch.install.optdeps.request.title=İsteğe bağlı bağımlılıklar -arch.install.repo_pkg.error.aur_deps=Depodaki paketin bağımlılığı olarak bir AUR paketi kurmak mümkün değildir arch.installing.package={} Paketi yükleniyor arch.checking_unnecessary_deps=Artık gerekli olmayan paketler olup olmadığını kontrol et arch.makepkg.optimizing=Derlemeyi optimize et