From ffa32a85b79c3eb72c66e730aedf9f52a2835b76 Mon Sep 17 00:00:00 2001 From: Vinicius Moreira Date: Sat, 5 Nov 2022 14:19:28 -0300 Subject: [PATCH] [gems.arch] fix: not considering some conflict expressions when retrieving upgrade requirements --- CHANGELOG.md | 1 + bauh/gems/arch/pacman.py | 17 ++++++++++++++++- bauh/gems/arch/updates.py | 35 +++++++++++++++++++++-------------- 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c545cbb..7f621818 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - some desktop entries not being displayed on the desktop environment menu (requires the AppImage to be reinstalled) [#287](https://github.com/vinifmor/bauh/issues/287) - Arch - not detecting some package replacements when upgrading due to conflict information having logic operators (e.g: `at-spi2-core: 2.44.1 -> 2.46.0` should replace the installed `at-spi2-atk: 2.38`) + - not considering some conflict expressions when retrieving upgrade requirements (it could lead to a system breakage depending on the conflict) - Debian - not properly handling packages with names ending with `:i386` [#298](https://github.com/vinifmor/bauh/issues/298) - Packaging diff --git a/bauh/gems/arch/pacman.py b/bauh/gems/arch/pacman.py index 9b33b9a7..15ce12a2 100644 --- a/bauh/gems/arch/pacman.py +++ b/bauh/gems/arch/pacman.py @@ -5,7 +5,7 @@ import shutil import traceback from io import StringIO from threading import Thread -from typing import List, Set, Tuple, Dict, Iterable, Optional, Any, Pattern +from typing import List, Set, Tuple, Dict, Iterable, Optional, Any, Pattern, Collection from colorama import Fore @@ -1081,3 +1081,18 @@ def map_available_packages() -> Optional[Dict[str, Any]]: 'r': package_data[0].strip(), 'i': len(package_data) == 4 and 'installed' in package_data[3]} return res + + +def map_installed(pkgs: Optional[Collection[str]] = None) -> Optional[Dict[str, str]]: + output = run_cmd(f"pacman -Q {' '.join({*pkgs} if pkgs else '')}".strip(), print_error=False) + + if output: + res = dict() + for raw_line in output.split("\n"): + line = raw_line.strip() + + if line: + pkg_version = line.split(" ") + if len(pkg_version) == 2: + res[pkg_version[0]] = pkg_version[1] + return res diff --git a/bauh/gems/arch/updates.py b/bauh/gems/arch/updates.py index 75f77425..9ec192bf 100644 --- a/bauh/gems/arch/updates.py +++ b/bauh/gems/arch/updates.py @@ -22,7 +22,7 @@ class UpdateRequirementsContext: aur_to_update: Dict[str, ArchPackage], repo_to_install: Dict[str, ArchPackage], aur_to_install: Dict[str, ArchPackage], to_install: Dict[str, ArchPackage], pkgs_data: Dict[str, dict], cannot_upgrade: Dict[str, UpgradeRequirement], - to_remove: Dict[str, UpgradeRequirement], installed_names: Set[str], provided_map: Dict[str, Set[str]], + to_remove: Dict[str, UpgradeRequirement], installed_names: Dict[str, str], provided_map: Dict[str, Set[str]], aur_index: Set[str], arch_config: dict, remote_provided_map: Dict[str, Set[str]], remote_repo_map: Dict[str, str], root_password: Optional[str], aur_supported: bool): self.to_update = to_update @@ -33,7 +33,7 @@ class UpdateRequirementsContext: self.pkgs_data = pkgs_data self.cannot_upgrade = cannot_upgrade self.root_password = root_password - self.installed_names = installed_names + self.installed = installed_names self.provided_map = provided_map self.to_remove = to_remove self.to_install = to_install @@ -150,13 +150,20 @@ class UpdatesSummarizer: if data['c']: for c in data['c']: if c: - pkg_name = DependenciesAnalyser.re_dep_operator().split(c)[0] - if pkg_name != p and pkg_name in context.installed_names: - # source = provided_map[c] - root_conflict[pkg_name] = p + name_op_exp = DependenciesAnalyser.re_dep_operator().split(c) + conflict_name = name_op_exp[0] - if (p, pkg_name) in root_conflict.items(): - mutual_conflicts[pkg_name] = p + if conflict_name != p: + conflict_version = context.installed.get(conflict_name) + + if conflict_version: + if len(name_op_exp) == 1 or match_required_version(conflict_version, + name_op_exp[1], + name_op_exp[2]): + root_conflict[conflict_name] = p + + if (p, conflict_name) in root_conflict.items(): + mutual_conflicts[conflict_name] = p if mutual_conflicts: for pkg1, pkg2 in mutual_conflicts.items(): @@ -280,8 +287,8 @@ class UpdatesSummarizer: ti = time.time() self.logger.info("Filling provided names") - if not context.installed_names: - context.installed_names = pacman.list_installed_names() + if not context.installed: + context.installed = pacman.map_installed() installed_to_ignore = set() @@ -307,8 +314,8 @@ class UpdatesSummarizer: if len(split_provided) > 1 and split_provided[0] != p: pacman.fill_provided_map(split_provided[0], pkgname, context.provided_map) - if installed_to_ignore: # filling the provided names of the installed - installed_to_query = context.installed_names.difference(installed_to_ignore) + if context.installed and installed_to_ignore: # filling the provided names of the installed + installed_to_query = {*context.installed}.difference(installed_to_ignore) if installed_to_query: context.provided_map.update(pacman.map_provided(remote=False, pkgs=installed_to_query)) @@ -376,7 +383,7 @@ class UpdatesSummarizer: remote_repo_map = pacman.map_repositories() context = UpdateRequirementsContext(to_update={}, repo_to_update={}, aur_to_update={}, repo_to_install={}, aur_to_install={}, to_install={}, pkgs_data={}, cannot_upgrade={}, - to_remove={}, installed_names=set(), provided_map={}, aur_index=set(), + to_remove={}, installed_names=dict(), provided_map={}, aur_index=set(), arch_config=arch_config, root_password=root_password, remote_provided_map=remote_provided_map, remote_repo_map=remote_repo_map, aur_supported=self.aur_supported) @@ -606,7 +613,7 @@ class UpdatesSummarizer: for r in reqs: if r in transaction_pkgs: reqs_in_transaction.add(r) - elif r in context.installed_names: + elif r in context.installed: reqs_not_in_transaction.add(r) if not reqs_not_in_transaction and not reqs_in_transaction: