From 293d2a5fb0484f23f5cc985d419daf65591cb424 Mon Sep 17 00:00:00 2001 From: Vinicius Moreira Date: Fri, 11 Sep 2020 11:17:27 -0300 Subject: [PATCH] [arch] fix -> uninstall: not detecting hard requirements properly --- CHANGELOG.md | 11 +- README.md | 4 +- bauh/commons/system.py | 5 + bauh/gems/arch/config.py | 4 +- bauh/gems/arch/controller.py | 203 ++++++++++++++++++----------- bauh/gems/arch/exceptions.py | 8 ++ bauh/gems/arch/pacman.py | 46 ++++++- bauh/gems/arch/resources/locale/ca | 5 + bauh/gems/arch/resources/locale/de | 5 + bauh/gems/arch/resources/locale/en | 5 + bauh/gems/arch/resources/locale/es | 5 + bauh/gems/arch/resources/locale/it | 5 + bauh/gems/arch/resources/locale/pt | 5 + bauh/gems/arch/resources/locale/ru | 5 + bauh/gems/arch/resources/locale/tr | 5 + 15 files changed, 235 insertions(+), 86 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bef3bb6..63b85d57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,6 +59,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

- allowing the user to bypass dependency breakage scenarios (a popup will be displayed) + - new settings property **suggest_unneeded_uninstall**: defines if the dependencies apparently no longer necessary associated with the uninstalled packages should be suggested for uninstallation. When this property is enabled it automatically disables the property **suggest_optdep_uninstall**. Default: false (to prevent new users from making mistakes) + - new settings property **suggest_optdep_uninstall**: defines if the optional dependencies associated with uninstalled packages should be suggested for uninstallation. Only the optional dependencies that are not dependencies of other packages will be suggested. Default: false (to prevent new users from making mistakes) +

+ +

- AUR - caching the PKGBUILD file used for the package installation/upgrade/downgrade (**~/.cache/bauh/arch/installed/$pkgname/PKGBUILD**) @@ -104,10 +109,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - some conflict resolution scenarios when upgrading several packages - not handling conflicting files errors during the installation process - - some environment variables are not available during the common operations (install, upgrade, downgrade, uninstall, makepkg, launch) - - not displaying and uninstalling dependent packages during conflict resolutions - - not retrieving all packages that would break if a given package is uninstalled - displaying wrong progress during the upgrade process when there are packages to install and upgrade + - uninstall: not detecting hard requirements properly + - not displaying and uninstalling dependent packages during conflict resolutions + - some environment variables are not available during the common operations (install, upgrade, downgrade, uninstall, makepkg, launch) - AUR - info dialog of installed packages displays the latest PKGBUILD file instead of the one used for installation/upgrade/downgrade (the fix will only work for new installed packages) - multi-threaded download: not retrieving correctly some source files URLs (e.g: linux-xanmod-lts) diff --git a/README.md b/README.md index 390fd401..6fb25aa0 100644 --- a/README.md +++ b/README.md @@ -203,7 +203,9 @@ edit_aur_pkgbuild: false # if the AUR PKGBUILD file should be displayed for edi aur_build_dir: null # defines a custom build directory for AUR packages (a null value will point to /tmp/bauh/arch (non-root user) or /tmp/bauh_root/arch (root user)). Default: null. aur_remove_build_dir: true # it defines if a package's generated build directory should be removed after the operation is finished (installation, upgrading, ...). Options: true, false (default: true). aur_build_only_chosen : true # some AUR packages have a common file definition declaring several packages to be built. When this property is 'true' only the package the user select to install will be built (unless its name is different from those declared in the PKGBUILD base). With a 'null' value a popup asking if the user wants to build all of them will be displayed. 'false' will build and install all packages. Default: true. -check_dependency_breakage: true # If, during the verification of the update requirements, specific versions of dependencies must also be checked. Example: package A depends on version 1.0 of B. If A and B were selected to upgrade, and B would be upgrade to 2.0, then B would be excluded from the transaction. Default: true. +check_dependency_breakage: true # if, during the verification of the update requirements, specific versions of dependencies must also be checked. Example: package A depends on version 1.0 of B. If A and B were selected to upgrade, and B would be upgrade to 2.0, then B would be excluded from the transaction. Default: true. +suggest_unneeded_uninstall: false # if the dependencies apparently no longer necessary associated with the uninstalled packages should be suggested for uninstallation. When this property is enabled it automatically disables the property 'suggest_optdep_uninstall'. Default: false (to prevent new users from making mistakes) +suggest_optdep_uninstall: false # if the optional dependencies associated with uninstalled packages should be suggested for uninstallation. Only the optional dependencies that are not dependencies of other packages will be suggested. Default: false (to prevent new users from making mistakes) ``` - Required dependencies: - **pacman** diff --git a/bauh/commons/system.py b/bauh/commons/system.py index 08f4bc4a..2b130803 100644 --- a/bauh/commons/system.py +++ b/bauh/commons/system.py @@ -320,3 +320,8 @@ def check_enabled_services(*names: str) -> Dict[str, bool]: else: status = output.split('\n') return {s: status[i].strip().lower() == 'enabled' for i, s in enumerate(names) if s} + + +def execute(cmd: str, shell: bool = False) -> Tuple[int, str]: + p = subprocess.run(args=cmd.split(' ') if not shell else [cmd], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=shell) + return p.returncode, p.stdout.decode() diff --git a/bauh/gems/arch/config.py b/bauh/gems/arch/config.py index 402c0ce2..2fd89b1b 100644 --- a/bauh/gems/arch/config.py +++ b/bauh/gems/arch/config.py @@ -19,7 +19,9 @@ def read_config(update_file: bool = False) -> dict: 'aur_build_dir': None, 'aur_remove_build_dir': True, 'aur_build_only_chosen': True, - 'check_dependency_breakage': True} + 'check_dependency_breakage': True, + 'suggest_unneeded_uninstall': False, + 'suggest_optdep_uninstall': False} return read(CONFIG_FILE, template, update_file=update_file) diff --git a/bauh/gems/arch/controller.py b/bauh/gems/arch/controller.py index a13ca7fb..eac27bed 100644 --- a/bauh/gems/arch/controller.py +++ b/bauh/gems/arch/controller.py @@ -39,7 +39,7 @@ from bauh.gems.arch.aur import AURClient from bauh.gems.arch.config import read_config, get_build_dir from bauh.gems.arch.dependencies import DependenciesAnalyser from bauh.gems.arch.download import MultithreadedDownloadService, ArchDownloadException -from bauh.gems.arch.exceptions import PackageNotFoundException +from bauh.gems.arch.exceptions import PackageNotFoundException, PackageInHoldException from bauh.gems.arch.mapper import ArchDataMapper from bauh.gems.arch.model import ArchPackage from bauh.gems.arch.output import TransactionStatusHandler @@ -1140,7 +1140,7 @@ class ArchManager(SoftwareManager): return True - def _request_unncessary_uninstall_confirmation(self, uninstalled: Iterable[str], unnecessary: Iterable[str], watcher: ProcessWatcher) -> Optional[List[str]]: + def _request_unncessary_uninstall_confirmation(self, unnecessary: Iterable[str], watcher: ProcessWatcher) -> Optional[Set[str]]: reqs = [InputOption(label=p, value=p, icon_path=get_icon_path(), read_only=False) for p in unnecessary] reqs_select = MultipleSelectComponent(options=reqs, default_options=set(reqs), label="", max_per_line=3 if len(reqs) > 9 else 1) @@ -1150,7 +1150,7 @@ class ArchManager(SoftwareManager): deny_label=self.i18n['arch.uninstall.unnecessary.proceed'].capitalize(), confirmation_label=self.i18n['arch.uninstall.unnecessary.cancel'].capitalize(), window_cancel=False): - return reqs_select.get_selected_values() + return {*reqs_select.get_selected_values()} def _request_all_unncessary_uninstall_confirmation(self, pkgs: Iterable[str], context: TransactionContext): reqs = [InputOption(label=p, value=p, icon_path=get_icon_path(), read_only=True) for p in pkgs] @@ -1172,47 +1172,45 @@ class ArchManager(SoftwareManager): net_available = internet.is_available() if disk_loader else True - required_by = self.deps_analyser.map_all_required_by(names, set()) + hard_requirements = set() - if required_by: - target_provided = pacman.map_provided(pkgs={*names, *required_by}).keys() + for n in names: + try: + pkg_reqs = pacman.list_hard_requirements(n, self.logger) - if target_provided: - required_by_deps = pacman.map_all_deps(required_by, only_installed=True) + if pkg_reqs: + hard_requirements.update(pkg_reqs) + except PackageInHoldException: + context.watcher.show_message(title=self.i18n['error'].capitalize(), + body=self.i18n['arch.uninstall.error.hard_dep_in_hold'].format(bold(n)), + type_=MessageType.ERROR) + return False - if required_by_deps: - all_provided = pacman.map_provided() - - for pkg, deps in required_by_deps.items(): - target_required_by = 0 - for dep in deps: - dep_split = pacman.RE_DEP_OPERATORS.split(dep) - if dep_split[0] in target_provided or dep_split[0] in required_by: - dep_providers = all_provided.get(dep_split[0]) - - if dep_providers: - target_required_by += 1 if not dep_providers.difference(target_provided) else 0 - - if not target_required_by: - required_by.remove(pkg) - - self._update_progress(context, 50) + self._update_progress(context, 25) to_uninstall = set() to_uninstall.update(names) - if required_by: - to_uninstall.update(required_by) + if hard_requirements: + to_uninstall.update(hard_requirements) if not self._request_uninstall_confirmation(to_uninstall=names, - required=required_by, + required=hard_requirements, watcher=context.watcher): return False if remove_unneeded: - all_deps_map = pacman.map_all_deps(names=to_uninstall, only_installed=True) # retrieving the deps to check if they are still necessary + unnecessary_packages = pacman.list_post_uninstall_unneeded_packages(to_uninstall) + self.logger.info("Checking unnecessary optdeps") + + if context.config['suggest_optdep_uninstall']: + unnecessary_packages.update(self._list_opt_deps_with_no_hard_requirements(source_pkgs=to_uninstall)) + + self.logger.info("Packages no longer needed found: {}".format(len(unnecessary_packages))) else: - all_deps_map = None + unnecessary_packages = None + + self._update_progress(context, 50) if disk_loader and to_uninstall: # loading package instances in case the uninstall succeeds instances = self.read_installed(disk_loader=disk_loader, @@ -1234,60 +1232,50 @@ class ArchManager(SoftwareManager): self._update_progress(context, 70) - if all_deps_map: - context.watcher.change_substatus(self.i18n['arch.checking_unnecessary_deps']) - all_deps = set() + if unnecessary_packages: + unnecessary_to_uninstall = self._request_unncessary_uninstall_confirmation(unnecessary=unnecessary_packages, + watcher=context.watcher) - all_provided = pacman.map_provided(remote=False) - for deps in all_deps_map.values(): - for dep in deps: - real_deps = all_provided.get(dep) + if unnecessary_to_uninstall: + context.watcher.change_substatus(self.i18n['arch.checking_unnecessary_deps']) + unnecessary_requirements = set() - if real_deps: - all_deps.update(real_deps) + for pkg in unnecessary_to_uninstall: + try: + pkg_reqs = pacman.list_hard_requirements(pkg) - if all_deps: - self.logger.info("Mapping dependencies required packages of uninstalled packages") - alldeps_reqs = pacman.map_required_by(all_deps) + if pkg_reqs: + unnecessary_requirements.update(pkg_reqs) - no_longer_needed = set() - if alldeps_reqs: - for dep, reqs in alldeps_reqs.items(): - if not reqs: - no_longer_needed.add(dep) + except PackageInHoldException: + context.watcher.show_message(title=self.i18n['warning'].capitalize(), + body=self.i18n['arch.uninstall.error.hard_dep_in_hold'].format(bold(p)), + type_=MessageType.WARNING) - if no_longer_needed: - self.logger.info("{} packages no longer needed found".format(len(no_longer_needed))) - unnecessary_to_uninstall = self._request_unncessary_uninstall_confirmation(uninstalled=to_uninstall, - unnecessary=no_longer_needed, - watcher=context.watcher) + all_unnecessary_to_uninstall = {*unnecessary_to_uninstall, *unnecessary_requirements} - if unnecessary_to_uninstall: - unnecessary_to_uninstall_deps = pacman.list_unnecessary_deps(unnecessary_to_uninstall, all_provided) - all_unnecessary_to_uninstall = {*unnecessary_to_uninstall, *unnecessary_to_uninstall_deps} + if not unnecessary_requirements or self._request_all_unncessary_uninstall_confirmation(all_unnecessary_to_uninstall, context): + if disk_loader: # loading package instances in case the uninstall succeeds + unnecessary_instances = self.read_installed(disk_loader=disk_loader, + internet_available=net_available, + names=all_unnecessary_to_uninstall).installed + else: + unnecessary_instances = None - if not unnecessary_to_uninstall_deps or self._request_all_unncessary_uninstall_confirmation(all_unnecessary_to_uninstall, context): + unneded_uninstalled = self._uninstall_pkgs(all_unnecessary_to_uninstall, context.root_password, context.handler) - if disk_loader: # loading package instances in case the uninstall succeeds - unnecessary_instances = self.read_installed(disk_loader=disk_loader, - internet_available=net_available, - names=all_unnecessary_to_uninstall).installed - else: - unnecessary_instances = None + if unneded_uninstalled: + to_uninstall.update(all_unnecessary_to_uninstall) - unneded_uninstalled = self._uninstall_pkgs(all_unnecessary_to_uninstall, context.root_password, context.handler) - - if unneded_uninstalled: - to_uninstall.update(all_unnecessary_to_uninstall) - - if disk_loader and unnecessary_instances: # loading package instances in case the uninstall succeeds - for p in unnecessary_instances: - context.removed[p.name] = p - else: - self.logger.error("Could not uninstall some unnecessary packages") - context.watcher.print("Could not uninstall some unnecessary packages") + if disk_loader and unnecessary_instances: # loading package instances in case the uninstall succeeds + for p in unnecessary_instances: + context.removed[p.name] = p + else: + self.logger.error("Could not uninstall some unnecessary packages") + context.watcher.print("Could not uninstall some unnecessary packages") self._update_progress(context, 90) + if bool(context.config['clean_cached']): # cleaning old versions context.watcher.change_substatus(self.i18n['arch.uninstall.clean_cached.substatus']) if os.path.isdir('/var/cache/pacman/pkg'): @@ -1315,13 +1303,14 @@ class ArchManager(SoftwareManager): return TransactionResult.fail() removed = {} + arch_config = read_config() success = self._uninstall(TransactionContext(change_progress=True, - arch_config=read_config(), + arch_config=arch_config, watcher=watcher, root_password=root_password, handler=handler, removed=removed), - remove_unneeded=True, + remove_unneeded=arch_config['suggest_unneeded_uninstall'], names={pkg.name}, disk_loader=disk_loader) # to be able to return all uninstalled packages if success: @@ -1545,7 +1534,7 @@ class ArchManager(SoftwareManager): if context.removed is None: context.removed = {} - res = self._uninstall(context=context, names={conflicting_pkg}, disk_loader=context.disk_loader) + res = self._uninstall(context=context, names={conflicting_pkg}, disk_loader=context.disk_loader, remove_unneeded=False) context.restabilish_progress() return res @@ -2568,16 +2557,27 @@ class ArchManager(SoftwareManager): def get_screenshots(self, pkg: SoftwarePackage) -> List[str]: pass - def _gen_bool_selector(self, id_: str, label_key: str, tooltip_key: str, value: bool, max_width: int, capitalize_label: bool = True) -> SingleSelectComponent: + def _gen_bool_selector(self, id_: str, label_key: str, tooltip_key: str, value: bool, max_width: int, + capitalize_label: bool = True, label_params: Optional[list] = None, tooltip_params: Optional[list] = None) -> SingleSelectComponent: opts = [InputOption(label=self.i18n['yes'].capitalize(), value=True), InputOption(label=self.i18n['no'].capitalize(), value=False)] - return SingleSelectComponent(label=self.i18n[label_key], + lb = self.i18n[label_key] + + if label_params: + lb = lb.format(*label_params) + + tip = self.i18n[tooltip_key] + + if tooltip_params: + tip = tip.format(*tooltip_params) + + return SingleSelectComponent(label=lb, options=opts, default_option=[o for o in opts if o.value == value][0], max_per_line=len(opts), type_=SelectViewType.RADIO, - tooltip=self.i18n[tooltip_key], + tooltip=tip, max_width=max_width, id_=id_, capitalize_label=capitalize_label) @@ -2638,6 +2638,17 @@ class ArchManager(SoftwareManager): tooltip_key='arch.config.clean_cache.tip', value=bool(local_config['clean_cached']), max_width=max_width), + self._gen_bool_selector(id_='suggest_unneeded_uninstall', + label_key='arch.config.suggest_unneeded_uninstall', + tooltip_params=['"{}"'.format(self.i18n['arch.config.suggest_optdep_uninstall'])], + tooltip_key='arch.config.suggest_unneeded_uninstall.tip', + value=bool(local_config['suggest_unneeded_uninstall']), + max_width=max_width), + self._gen_bool_selector(id_='suggest_optdep_uninstall', + label_key='arch.config.suggest_optdep_uninstall', + tooltip_key='arch.config.suggest_optdep_uninstall.tip', + value=bool(local_config['suggest_optdep_uninstall']), + max_width=max_width), self._gen_bool_selector(id_='ref_mirs', label_key='arch.config.refresh_mirrors', tooltip_key='arch.config.refresh_mirrors.tip', @@ -2707,6 +2718,8 @@ class ArchManager(SoftwareManager): config['aur_build_dir'] = form_install.get_component('aur_build_dir').file_path config['aur_build_only_chosen'] = form_install.get_component('aur_build_only_chosen').get_selected() config['check_dependency_breakage'] = form_install.get_component('check_dependency_breakage').get_selected() + config['suggest_optdep_uninstall'] = form_install.get_component('suggest_optdep_uninstall').get_selected() + config['suggest_unneeded_uninstall'] = form_install.get_component('suggest_unneeded_uninstall').get_selected() if not config['aur_build_dir']: config['aur_build_dir'] = None @@ -3132,3 +3145,35 @@ class ArchManager(SoftwareManager): f.write(new_srcinfo) return custom_pkgbuild_path + + def _list_opt_deps_with_no_hard_requirements(self, source_pkgs: Set[str], installed_provided: Optional[Dict[str, Set[str]]] = None) -> Set[str]: + optdeps = set() + + for deps in pacman.map_optional_deps(names=source_pkgs, remote=False).values(): + optdeps.update(deps.keys()) + + res = set() + if optdeps: + all_provided = pacman.map_provided() if not installed_provided else installed_provided + + real_optdeps = set() + for o in optdeps: + dep_providers = all_provided.get(o) + + if dep_providers: + for p in dep_providers: + if p not in source_pkgs: + real_optdeps.add(p) + + if real_optdeps: + for p in real_optdeps: + try: + reqs = pacman.list_hard_requirements(p, self.logger) + + if reqs is not None and (not reqs or reqs.issubset(source_pkgs)): + res.add(p) + except PackageInHoldException: + self.logger.warning("There is a requirement in hold for opt dep '{}'".format(p)) + continue + + return res diff --git a/bauh/gems/arch/exceptions.py b/bauh/gems/arch/exceptions.py index d868cb15..a5c29584 100644 --- a/bauh/gems/arch/exceptions.py +++ b/bauh/gems/arch/exceptions.py @@ -1,5 +1,13 @@ +from typing import Optional + class PackageNotFoundException(Exception): def __init__(self, name: str): self.name = name + + +class PackageInHoldException(Exception): + + def __init__(self, name: Optional[str] = None): + self.name = name diff --git a/bauh/gems/arch/pacman.py b/bauh/gems/arch/pacman.py index 5c042d2d..18cd8000 100644 --- a/bauh/gems/arch/pacman.py +++ b/bauh/gems/arch/pacman.py @@ -1,12 +1,15 @@ +import logging import os import re from threading import Thread -from typing import List, Set, Tuple, Dict, Iterable +from typing import List, Set, Tuple, Dict, Iterable, Optional + +from colorama import Fore from bauh.commons import system from bauh.commons.system import run_cmd, new_subprocess, new_root_subprocess, SystemProcess, SimpleProcess from bauh.commons.util import size_to_byte -from bauh.gems.arch.exceptions import PackageNotFoundException +from bauh.gems.arch.exceptions import PackageNotFoundException, PackageInHoldException RE_DEPS = re.compile(r'[\w\-_]+:[\s\w_\-\.]+\s+\[\w+\]') RE_OPTDEPS = re.compile(r'[\w\._\-]+\s*:') @@ -1128,3 +1131,42 @@ def get_packages_to_sync_first() -> Set[str]: def is_snapd_installed() -> bool: return bool(run_cmd('pacman -Qq snapd', print_error=False)) + + +def list_hard_requirements(name: str, logger: Optional[logging.Logger] = None) -> Optional[Set[str]]: + code, output = system.execute('pacman -Rc {} --print-format=%n'.format(name), shell=True) + + if code != 0: + if 'HoldPkg' in output: + raise PackageInHoldException() + elif 'target not found' in output: + raise PackageNotFoundException(name) + elif logger: + logger.error("Unexpected error while listing hard requirements of: {}".format(name)) + print('{}{}{}'.format(Fore.RED, output, Fore.RESET)) + elif output: + reqs = set() + + for line in output.split('\n'): + if line: + line_strip = line.strip() + + if line_strip and line_strip != name: + reqs.add(line_strip) + + return reqs + + +def list_post_uninstall_unneeded_packages(names: Set[str]) -> Set[str]: + output = run_cmd('pacman -Rss {} --print-format=%n'.format(' '.join(names)), print_error=False) + + reqs = set() + if output: + for line in output.split('\n'): + if line: + line_strip = line.strip() + + if line_strip and line_strip not in names: + reqs.add(line_strip) + + return reqs diff --git a/bauh/gems/arch/resources/locale/ca b/bauh/gems/arch/resources/locale/ca index 5d6c2a5e..410cd4c1 100644 --- a/bauh/gems/arch/resources/locale/ca +++ b/bauh/gems/arch/resources/locale/ca @@ -56,6 +56,10 @@ arch.config.refresh_mirrors=Refresh mirrors on startup arch.config.refresh_mirrors.tip=Refresh the package mirrors once a day on startup ( or after a device reboot ) arch.config.repos=Repositories packages arch.config.repos.tip=It allows to manage packages from the repositories set +arch.config.suggest_optdep_uninstall=Uninstall optional dependencies +arch.config.suggest_optdep_uninstall.tip=If the optional dependencies associated with uninstalled packages should be suggested for uninstallation. Only the optional dependencies that are not dependencies of other packages will be suggested. +arch.config.suggest_unneeded_uninstall=Uninstall unneeded dependencies +arch.config.suggest_unneeded_uninstall.tip=If the dependencies apparently no longer necessary associated with the uninstalled packages should be suggested for uninstallation. When this property is enabled it automatically disables the property {}. arch.config.sync_dbs=Synchronize packages databases arch.config.sync_dbs.tip=Synchronizes the package databases once a day before the first package installation, upgrade or downgrade. This option helps to prevent errors during these operations. arch.config.sync_dbs_start.tip=Synchronizes the package databases during the initialization once a day @@ -213,6 +217,7 @@ arch.task.sync_sb.status=Actualitzen {} arch.uncompressing.package=S’està descomprimint el paquet arch.uninstall.clean_cached.error=No s'ha pogut eliminar {} versions antigues que es troba al disc arch.uninstall.clean_cached.substatus=Eliminació de versions antigues del disc +arch.uninstall.error.hard_dep_in_hold=It is not possible to uninstall {} because one of its dependencies is marked as "InHold" arch.uninstall.required_by=The {} packages listed below depend on {} to work properly arch.uninstall.required_by.advice=It is necessary to uninstall them as well to proceed arch.uninstall.unnecessary.all=The following {} packages will be uninstalled diff --git a/bauh/gems/arch/resources/locale/de b/bauh/gems/arch/resources/locale/de index 827fcaf0..55120a11 100644 --- a/bauh/gems/arch/resources/locale/de +++ b/bauh/gems/arch/resources/locale/de @@ -56,6 +56,10 @@ arch.config.refresh_mirrors=Refresh mirrors on startup arch.config.refresh_mirrors.tip=Refresh the package mirrors once a day on startup ( or after a device reboot ) arch.config.repos=Repositories packages arch.config.repos.tip=It allows to manage packages from the repositories set +arch.config.suggest_optdep_uninstall=Uninstall optional dependencies +arch.config.suggest_optdep_uninstall.tip=If the optional dependencies associated with uninstalled packages should be suggested for uninstallation. Only the optional dependencies that are not dependencies of other packages will be suggested. +arch.config.suggest_unneeded_uninstall=Uninstall unneeded dependencies +arch.config.suggest_unneeded_uninstall.tip=If the dependencies apparently no longer necessary associated with the uninstalled packages should be suggested for uninstallation. When this property is enabled it automatically disables the property {}. arch.config.sync_dbs=Synchronize packages databases arch.config.sync_dbs.tip=Synchronizes the package databases once a day before the first package installation, upgrade or downgrade. This option helps to prevent errors during these operations. arch.config.sync_dbs_start.tip=Synchronizes the package databases during the initialization once a day @@ -213,6 +217,7 @@ arch.task.sync_sb.status=Updating {} arch.uncompressing.package=Paket entpacken arch.uninstall.clean_cached.error=It was not possible to remove old {} versions found on disk arch.uninstall.clean_cached.substatus=Removing old versions from disk +arch.uninstall.error.hard_dep_in_hold=It is not possible to uninstall {} because one of its dependencies is marked as "InHold" arch.uninstall.required_by=The {} packages listed below depend on {} to work properly arch.uninstall.required_by.advice=It is necessary to uninstall them as well to proceed arch.uninstall.unnecessary.all=The following {} packages will be uninstalled diff --git a/bauh/gems/arch/resources/locale/en b/bauh/gems/arch/resources/locale/en index c85e103a..e8a940b6 100644 --- a/bauh/gems/arch/resources/locale/en +++ b/bauh/gems/arch/resources/locale/en @@ -57,6 +57,10 @@ arch.config.refresh_mirrors=Refresh mirrors on startup arch.config.refresh_mirrors.tip=Refresh the package mirrors once a day on startup ( or after a device reboot ) arch.config.repos=Repositories packages arch.config.repos.tip=It allows to manage packages from the repositories set +arch.config.suggest_optdep_uninstall=Uninstall optional dependencies +arch.config.suggest_optdep_uninstall.tip=If the optional dependencies associated with uninstalled packages should be suggested for uninstallation. Only the optional dependencies that are not dependencies of other packages will be suggested. +arch.config.suggest_unneeded_uninstall=Uninstall unneeded dependencies +arch.config.suggest_unneeded_uninstall.tip=If the dependencies apparently no longer necessary associated with the uninstalled packages should be suggested for uninstallation. When this property is enabled it automatically disables the property {}. arch.config.sync_dbs=Synchronize packages databases arch.config.sync_dbs.tip=Synchronizes the package databases once a day before the first package installation, upgrade or downgrade. This option helps to prevent errors during these operations. arch.config.sync_dbs_start.tip=Synchronizes the package databases during the initialization once a day @@ -214,6 +218,7 @@ arch.task.sync_sb.status=Updating {} arch.uncompressing.package=Uncompressing the package arch.uninstall.clean_cached.error=It was not possible to remove old {} versions found on disk arch.uninstall.clean_cached.substatus=Removing old versions from disk +arch.uninstall.error.hard_dep_in_hold=It is not possible to uninstall {} because one of its dependencies is marked as "InHold" arch.uninstall.required_by=The {} packages listed below depend on {} to work properly arch.uninstall.required_by.advice=It is necessary to uninstall them as well to proceed arch.uninstall.unnecessary.all=The following {} packages will be uninstalled diff --git a/bauh/gems/arch/resources/locale/es b/bauh/gems/arch/resources/locale/es index 32127891..6eb584b1 100644 --- a/bauh/gems/arch/resources/locale/es +++ b/bauh/gems/arch/resources/locale/es @@ -56,6 +56,10 @@ arch.config.refresh_mirrors=Actualizar espejos al iniciar arch.config.refresh_mirrors.tip=Actualiza los espejos de paquetes una vez al día al iniciar ( o después de reiniciar el dispositivo ) arch.config.repos=Paquetes de repositorios arch.config.repos.tip=Permite gestionar paquetes de los repositorios configurados +arch.config.suggest_optdep_uninstall=Desinstalar dependencias opcionales +arch.config.suggest_optdep_uninstall.tip=Si las dependencias opcionales asociadas con los paquetes desinstalados deben se sugeridas para desinstalación. Solo se sugerirán las dependencias opcionales que no sean dependencias de otros paquetes. +arch.config.suggest_unneeded_uninstall=Desinstalar las dependencias innecesarias +arch.config.suggest_unneeded_uninstall.tip=Si las dependencias aparentemente ya no necesarias asociadas con los paquetes desinstalados deben ser sugeridas para desinstalación. Cuando esta propiedad está habilitada, automáticamente deshabilita la propiedad {}. arch.config.sync_dbs=Sincronizar las bases de paquetes arch.config.sync_dbs.tip=Sincroniza las bases de paquetes una vez al día antes de la primera instalación, actualización o reversión de paquete. Esta opción ayuda a prevenir errores durante estas operaciones. arch.config.sync_dbs_start.tip=Sincroniza las bases de paquetes durante la inicialización una vez al día @@ -213,6 +217,7 @@ arch.task.sync_sb.status=Actualizando {} arch.uncompressing.package=Descomprimindo el paquete arch.uninstall.clean_cached.error=No fue posible eliminar versiones antiguas de {} encontradas en disco arch.uninstall.clean_cached.substatus=Eliminando versiones antiguas del disco +arch.uninstall.error.hard_dep_in_hold=No es posible desinstalar {} porque una de sus dependencias está bloqueada (InHold) arch.uninstall.required_by=Los {} paquetes enumerados abajo dependen de {} para funcionar correctamente arch.uninstall.required_by.advice=Es necesario desinstalarlos también para continuar arch.uninstall.unnecessary.all=Los {} seguintes paquetes serán desinstalados diff --git a/bauh/gems/arch/resources/locale/it b/bauh/gems/arch/resources/locale/it index d576ef8d..003d5536 100644 --- a/bauh/gems/arch/resources/locale/it +++ b/bauh/gems/arch/resources/locale/it @@ -56,6 +56,10 @@ arch.config.refresh_mirrors=Refresh mirrors on startup arch.config.refresh_mirrors.tip=Refresh the package mirrors once a day on startup ( or after a device reboot ) arch.config.repos=Repositories packages arch.config.repos.tip=It allows to manage packages from the repositories set +arch.config.suggest_optdep_uninstall=Uninstall optional dependencies +arch.config.suggest_optdep_uninstall.tip=If the optional dependencies associated with uninstalled packages should be suggested for uninstallation. Only the optional dependencies that are not dependencies of other packages will be suggested. +arch.config.suggest_unneeded_uninstall=Uninstall unneeded dependencies +arch.config.suggest_unneeded_uninstall.tip=If the dependencies apparently no longer necessary associated with the uninstalled packages should be suggested for uninstallation. When this property is enabled it automatically disables the property {}. arch.config.sync_dbs=Synchronize packages databases arch.config.sync_dbs.tip=Synchronizes the package databases once a day before the first package installation, upgrade or downgrade. This option helps to prevent errors during these operations. arch.config.sync_dbs_start.tip=Synchronizes the package databases during the initialization once a day @@ -213,6 +217,7 @@ arch.task.sync_sb.status=Aggiornando {} arch.uncompressing.package=Non comprimere il pacchetto arch.uninstall.clean_cached.error=Non è stato possibile rimuovere le vecchie {} versioni trovate sul disco arch.uninstall.clean_cached.substatus=Rimozione di versioni precedenti dal disco +arch.uninstall.error.hard_dep_in_hold=It is not possible to uninstall {} because one of its dependencies is marked as "InHold" arch.uninstall.required_by=The {} packages listed below depend on {} to work properly arch.uninstall.required_by.advice=It is necessary to uninstall them as well to proceed arch.uninstall.unnecessary.all=The following {} packages will be uninstalled diff --git a/bauh/gems/arch/resources/locale/pt b/bauh/gems/arch/resources/locale/pt index d1ef855f..4b7e43fd 100644 --- a/bauh/gems/arch/resources/locale/pt +++ b/bauh/gems/arch/resources/locale/pt @@ -56,6 +56,10 @@ arch.config.refresh_mirrors=Atualizar espelhos ao iniciar arch.config.refresh_mirrors.tip=Atualiza os espelhos de pacotes uma vez ao dia na inicialização arch.config.repos=Pacotes de repositórios arch.config.repos.tip=Permite gerenciar pacotes dos repositórisos +arch.config.suggest_optdep_uninstall=Desinstalar dependências opcionais +arch.config.suggest_optdep_uninstall.tip=Se as dependências opcionais associadas a pacotes desinstalados devem ser sugeridas para desinstalação. Somente as dependências opcionais que não sejam dependências de outros pacotes serão sugeridas. +arch.config.suggest_unneeded_uninstall=Desinstalar dependências desnecessárias +arch.config.suggest_unneeded_uninstall.tip=Se as dependências aparentemente não mais necessárias associadas aos pacotes desinstalados devem ser sugeridas para desinstalação. Quando essa proprieda está habilitada automaticamente desabilita a propriedade {}. arch.config.sync_dbs=Sincronizar bases de pacotes arch.config.sync_dbs.tip=Sincroniza as bases de pacotes uma vez ao dia antes da primeira instalação, atualização ou reversão de pacote. Essa opção ajuda a evitar erros durante essa operações. arch.config.sync_dbs_start.tip=Sincroniza as bases de pacotes durante a inicialização uma vez ao dia @@ -213,6 +217,7 @@ arch.task.sync_sb.status=Atualizando {} arch.uncompressing.package=Descompactando o pacote arch.uninstall.clean_cached.error=Não foi possível remover versões antigas de {} encontradas em disco arch.uninstall.clean_cached.substatus=Removendo versões antigas do disco +arch.uninstall.error.hard_dep_in_hold=Não é possível desinstalar {} pois uma de suas dependências está bloqueada (InHold) arch.uninstall.required_by=Os {} pacotes listados abaixo dependem de {} para funcionar corretamente arch.uninstall.required_by.advice=Para prosseguir será necessário desinstá-los também arch.uninstall.unnecessary.all=Os seguintes {} pacotes serão desinstalados diff --git a/bauh/gems/arch/resources/locale/ru b/bauh/gems/arch/resources/locale/ru index 751f10b1..035ce7cb 100644 --- a/bauh/gems/arch/resources/locale/ru +++ b/bauh/gems/arch/resources/locale/ru @@ -56,6 +56,10 @@ arch.config.refresh_mirrors=Обновить зеркала при запуск arch.config.refresh_mirrors.tip=Обновляйте зеркала пакета один раз в день при запуске (или после перезагрузки устройства) arch.config.repos=Пакеты репозиториев arch.config.repos.tip=Он позволяет управлять пакетами из набора репозиториев +arch.config.suggest_optdep_uninstall=Uninstall optional dependencies +arch.config.suggest_optdep_uninstall.tip=If the optional dependencies associated with uninstalled packages should be suggested for uninstallation. Only the optional dependencies that are not dependencies of other packages will be suggested. +arch.config.suggest_unneeded_uninstall=Uninstall unneeded dependencies +arch.config.suggest_unneeded_uninstall.tip=If the dependencies apparently no longer necessary associated with the uninstalled packages should be suggested for uninstallation. When this property is enabled it automatically disables the property {}. arch.config.sync_dbs=Синхронизация баз данных пакетов arch.config.sync_dbs.tip=Синхронизируйте базы данных пакетов один раз в день перед первой установкой, обновлением или понижением версии пакета. Этот параметр помогает предотвратить ошибки во время этих операций. arch.config.sync_dbs_start.tip=Синхронизирует базы данных пакетов во время инициализации один раз в день @@ -213,6 +217,7 @@ arch.task.sync_sb.status=Updating {} arch.uncompressing.package=Распаковка пакета arch.uninstall.clean_cached.error=It was not possible to remove old {} versions found on disk arch.uninstall.clean_cached.substatus=Removing old versions from disk +arch.uninstall.error.hard_dep_in_hold=It is not possible to uninstall {} because one of its dependencies is marked as "InHold" arch.uninstall.required_by=The {} packages listed below depend on {} to work properly arch.uninstall.required_by.advice=It is necessary to uninstall them as well to proceed arch.uninstall.unnecessary.all=The following {} packages will be uninstalled diff --git a/bauh/gems/arch/resources/locale/tr b/bauh/gems/arch/resources/locale/tr index 023bea68..a6a12a76 100644 --- a/bauh/gems/arch/resources/locale/tr +++ b/bauh/gems/arch/resources/locale/tr @@ -56,6 +56,10 @@ arch.config.refresh_mirrors=Başlangıçta yansıları yenile arch.config.refresh_mirrors.tip=Paket yansılarını başlangıçta günde bir kez (veya cihaz yeniden başlatıldıktan sonra) yenileyin arch.config.repos=Depo paketleri arch.config.repos.tip=Paketleri depolardan yönetmeye izin verir +arch.config.suggest_optdep_uninstall=Uninstall optional dependencies +arch.config.suggest_optdep_uninstall.tip=If the optional dependencies associated with uninstalled packages should be suggested for uninstallation. Only the optional dependencies that are not dependencies of other packages will be suggested. +arch.config.suggest_unneeded_uninstall=Uninstall unneeded dependencies +arch.config.suggest_unneeded_uninstall.tip=If the dependencies apparently no longer necessary associated with the uninstalled packages should be suggested for uninstallation. When this property is enabled it automatically disables the property {}. arch.config.sync_dbs=Paket veritabanlarını senkronize et arch.config.sync_dbs.tip=İlk veritabanını kurmadan, yükseltmeden veya indirmeden önce paket veritabanlarını günde bir kez senkronize eder. Bu seçenek, bu işlemler sırasında hataların önlenmesine yardımcı olur. arch.config.sync_dbs_start.tip=Başlatma sırasında paket veritabanlarını günde bir kez senkronize eder @@ -213,6 +217,7 @@ arch.task.sync_sb.status={} güncelleniyor arch.uncompressing.package=Paket arşivden çıkarılıyor arch.uninstall.clean_cached.error=Diskte bulunan eski {} sürümleri kaldırılamadı arch.uninstall.clean_cached.substatus=Eski sürümler diskten kaldırılıyor +arch.uninstall.error.hard_dep_in_hold=It is not possible to uninstall {} because one of its dependencies is marked as "InHold" arch.uninstall.required_by=The {} packages listed below depend on {} to work properly arch.uninstall.required_by.advice=Devam etmek için bunları da kaldırmak gerekir arch.uninstall.unnecessary.all=Aşağıdaki {} paketler kaldırılacak