From 268b59bc3a2df345986b99e55de70d64ffffcb15 Mon Sep 17 00:00:00 2001 From: Vinicius Moreira Date: Wed, 13 Apr 2022 17:47:07 -0300 Subject: [PATCH] [arch] fix: displaying already installed packages when suggesting optional dependencies --- CHANGELOG.md | 3 ++ bauh/gems/arch/pacman.py | 43 ++++++++++----------- tests/gems/arch/test_pacman.py | 70 ++++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e04388a5..50975b16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - not properly converting bibyte (KiB, MiB, ...) and byte (kB, MB, ...) based sizes to bytes - uninstall and downgrade logs are not available [#255](https://github.com/vinifmor/bauh/issues/255) +- Arch: + - displaying already installed packages when suggesting optional dependencies + - Debian - install/upgrade: hanging when packages require manual configuration - info: crashing when the package size has unexpected symbols [#251](https://github.com/vinifmor/bauh/issues/251) diff --git a/bauh/gems/arch/pacman.py b/bauh/gems/arch/pacman.py index 4a4ac20b..5f27b1bb 100644 --- a/bauh/gems/arch/pacman.py +++ b/bauh/gems/arch/pacman.py @@ -725,16 +725,26 @@ def remove_several(pkgnames: Iterable[str], root_password: Optional[str], skip_c return SimpleProcess(cmd=cmd, root_password=root_password, wrong_error_phrases={'warning:'}, shell=True) +def _map_optional_dep(line: str, not_installed: bool) -> Optional[Tuple[str, Optional[str]]]: + if not not_installed or not line.endswith('[installed]'): + pkg_desc = line.split(':') + + if len(pkg_desc) == 1: + return pkg_desc[0].split('[installed]')[0].strip(), '' + elif len(pkg_desc) > 1: + return pkg_desc[0], pkg_desc[1].split('[installed]')[0].strip() + + def map_optional_deps(names: Iterable[str], remote: bool, not_installed: bool = False) -> Dict[str, Dict[str, str]]: output = run_cmd('pacman -{}i {}'.format('S' if remote else 'Q', ' '.join(names))) res = {} if output: latest_name, deps = None, None - for l in output.split('\n'): - if l: - if l[0] != ' ': - line = l.strip() + for raw_line in output.split('\n'): + if raw_line: + if raw_line[0] != ' ': + line = raw_line.strip() field_sep_idx = line.index(':') field = line[0:field_sep_idx].strip() @@ -745,33 +755,20 @@ def map_optional_deps(names: Iterable[str], remote: bool, not_installed: bool = val = line[field_sep_idx + 1:].strip() deps = {} if val != 'None': - if ':' in val: - dep_info = val.split(':') - desc = dep_info[1].strip() + dep_desc = _map_optional_dep(val, not_installed) - if desc and not_installed and '[installed]' in desc: - continue + if dep_desc: + deps[dep_desc[0]] = dep_desc[1] - deps[dep_info[0].strip()] = desc - else: - sev_deps = {dep.strip(): '' for dep in val.split(' ') if dep and (not not_installed or '[installed]' not in dep)} - deps.update(sev_deps) elif latest_name and deps is not None: res[latest_name] = deps latest_name, deps = None, None elif latest_name and deps is not None: - if ':' in l: - dep_info = l.split(':') - desc = dep_info[1].strip() + dep_desc = _map_optional_dep(raw_line.strip(), not_installed) - if desc and not_installed and '[installed]' in desc: - continue - - deps[dep_info[0].strip()] = desc - else: - sev_deps = {dep.strip(): '' for dep in l.split(' ') if dep and (not not_installed or '[installed]' not in dep)} - deps.update(sev_deps) + if dep_desc: + deps[dep_desc[0]] = dep_desc[1] return res diff --git a/tests/gems/arch/test_pacman.py b/tests/gems/arch/test_pacman.py index 7fd20221..0ce047a6 100644 --- a/tests/gems/arch/test_pacman.py +++ b/tests/gems/arch/test_pacman.py @@ -1,7 +1,9 @@ import os import warnings from unittest import TestCase +from unittest.mock import patch, Mock +from bauh import __app_name__ from bauh.gems.arch import pacman FILE_DIR = os.path.dirname(os.path.abspath(__file__)) @@ -26,3 +28,71 @@ class PacmanTest(TestCase): self.assertIsNotNone(ignored) self.assertEqual(0, len(ignored)) + + @patch(f'{__app_name__}.gems.arch.pacman.run_cmd', return_value=""" +Name : package-test +Version : 3.4.4-1 +Description : Test +Depends On : embree freetype2 libglvnd +Optional Deps : lib32-vulkan-icd-loader: Vulkan support [installed] +Required By : None + """) + def test_map_optional_deps__no_remote_and_not_installed__only_one_installed_with_description(self, run_cmd: Mock): + res = pacman.map_optional_deps(('package-test',), remote=False, not_installed=True) + run_cmd.assert_called_once_with('pacman -Qi package-test') + self.assertEqual({'package-test': {}}, res) + + @patch(f'{__app_name__}.gems.arch.pacman.run_cmd', return_value=""" +Name : package-test +Version : 3.4.4-1 +Description : Test +Depends On : embree freetype2 libglvnd +Optional Deps : lib32-vulkan-icd-loader: Vulkan support +Required By : None + """) + def test_map_optional_deps__no_remote_and_not_installed__only_one_not_installed_with_description(self, run_cmd: Mock): + res = pacman.map_optional_deps(('package-test',), remote=False, not_installed=True) + run_cmd.assert_called_once_with('pacman -Qi package-test') + self.assertEqual({'package-test': {'lib32-vulkan-icd-loader': 'Vulkan support'}}, res) + + @patch(f'{__app_name__}.gems.arch.pacman.run_cmd', return_value=""" +Name : package-test +Version : 3.4.4-1 +Description : Test +Depends On : embree freetype2 libglvnd +Optional Deps : pipewire-alsa +Required By : None + """) + def test_map_optional_deps__no_remote_and_not_installed__only_one_not_installed_no_description(self, run_cmd: Mock): + res = pacman.map_optional_deps(('package-test',), remote=False, not_installed=True) + run_cmd.assert_called_once_with('pacman -Qi package-test') + self.assertEqual({'package-test': {'pipewire-alsa': ''}}, res) + + @patch(f'{__app_name__}.gems.arch.pacman.run_cmd', return_value=""" +Name : package-test +Version : 3.4.4-1 +Description : Test +Depends On : embree freetype2 libglvnd +Optional Deps : pipewire-alsa [installed] +Required By : None + """) + def test_map_optional_deps__no_remote_and_not_installed__only_one_installed_no_description(self, run_cmd: Mock): + res = pacman.map_optional_deps(('package-test',), remote=False, not_installed=True) + run_cmd.assert_called_once_with('pacman -Qi package-test') + self.assertEqual({'package-test': {}}, res) + + @patch(f'{__app_name__}.gems.arch.pacman.run_cmd', return_value=""" +Name : package-test +Version : 3.4.4-1 +Description : Test +Depends On : embree freetype2 libglvnd libtheora +Optional Deps : pipewire-alsa + pipewire-pulse [installed] + pipewire + lib32-vulkan-icd-loader: Vulkan support [installed] +Required By : None + """) + def test_map_optional_deps__no_remote_and_not_installed__several(self, run_cmd: Mock): + res = pacman.map_optional_deps(('package-test',), remote=False, not_installed=True) + run_cmd.assert_called_once_with('pacman -Qi package-test') + self.assertEqual({'package-test': {'pipewire-alsa': '', 'pipewire': ''}}, res)