mirror of
https://github.com/spalencsar/bearhub.git
synced 2026-07-07 01:14:15 +02:00
[arch] fix: some dependencies not being matched during comparisons between numeric and alphanumeric versions
This commit is contained in:
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
|
## [0.9.18]
|
||||||
|
### Fixes
|
||||||
|
- Arch
|
||||||
|
- install/upgrade/downgrade: some dependencies not being matched during comparisons between numeric and alphanumeric versions
|
||||||
|
|
||||||
|
|
||||||
## [0.9.17] 2021-06-16
|
## [0.9.17] 2021-06-16
|
||||||
### Improvements
|
### Improvements
|
||||||
- general: replacing subprocess commands to detect installed CLIs by Python faster calls (**shutil.which**)
|
- general: replacing subprocess commands to detect installed CLIs by Python faster calls (**shutil.which**)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
__version__ = '0.9.17'
|
__version__ = '0.9.18'
|
||||||
__app_name__ = 'bauh'
|
__app_name__ = 'bauh'
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|||||||
@@ -3,13 +3,11 @@ import traceback
|
|||||||
from threading import Thread
|
from threading import Thread
|
||||||
from typing import Set, List, Tuple, Dict, Iterable, Optional
|
from typing import Set, List, Tuple, Dict, Iterable, Optional
|
||||||
|
|
||||||
from packaging.version import parse as parse_version
|
|
||||||
|
|
||||||
from bauh.api.abstract.handler import ProcessWatcher
|
from bauh.api.abstract.handler import ProcessWatcher
|
||||||
from bauh.gems.arch import pacman, message, sorting, confirmation
|
from bauh.gems.arch import pacman, message, sorting, confirmation
|
||||||
from bauh.gems.arch.aur import AURClient
|
from bauh.gems.arch.aur import AURClient
|
||||||
from bauh.gems.arch.exceptions import PackageNotFoundException
|
from bauh.gems.arch.exceptions import PackageNotFoundException
|
||||||
from bauh.gems.arch.util import clean_version
|
from bauh.gems.arch.version import compare_versions
|
||||||
from bauh.view.util.translation import I18n
|
from bauh.view.util.translation import I18n
|
||||||
|
|
||||||
|
|
||||||
@@ -220,7 +218,7 @@ class DependenciesAnalyser:
|
|||||||
matched_providers = set()
|
matched_providers = set()
|
||||||
split_informed_dep = self.re_dep_operator.split(dep_exp)
|
split_informed_dep = self.re_dep_operator.split(dep_exp)
|
||||||
try:
|
try:
|
||||||
version_required = parse_version(clean_version(split_informed_dep[2]))
|
version_required = split_informed_dep[2]
|
||||||
exp_op = split_informed_dep[1] if split_informed_dep[1] != '=' else '=='
|
exp_op = split_informed_dep[1] if split_informed_dep[1] != '=' else '=='
|
||||||
|
|
||||||
for p in providers:
|
for p in providers:
|
||||||
@@ -230,9 +228,9 @@ class DependenciesAnalyser:
|
|||||||
split_dep = self.re_dep_operator.split(provided_exp)
|
split_dep = self.re_dep_operator.split(provided_exp)
|
||||||
|
|
||||||
if len(split_dep) == 3 and split_dep[0] == dep_name:
|
if len(split_dep) == 3 and split_dep[0] == dep_name:
|
||||||
version_provided = parse_version(clean_version(split_dep[2]))
|
version_provided = split_dep[2]
|
||||||
|
|
||||||
if eval('version_provided {} version_required'.format(exp_op)):
|
if compare_versions(version_provided, exp_op, version_required):
|
||||||
matched_providers.add(p)
|
matched_providers.add(p)
|
||||||
break
|
break
|
||||||
|
|
||||||
@@ -270,17 +268,17 @@ class DependenciesAnalyser:
|
|||||||
self.__raise_dependency_not_found(dep_exp, watcher)
|
self.__raise_dependency_not_found(dep_exp, watcher)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
dep_version = parse_version(clean_version(dep_info[0]['Version']))
|
dep_version = dep_info[0]['Version']
|
||||||
except:
|
except:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
self.__raise_dependency_not_found(dep_exp, watcher)
|
return self.__raise_dependency_not_found(dep_exp, watcher)
|
||||||
|
|
||||||
split_informed_dep = self.re_dep_operator.split(dep_exp)
|
split_informed_dep = self.re_dep_operator.split(dep_exp)
|
||||||
try:
|
try:
|
||||||
version_required = parse_version(clean_version(split_informed_dep[2]))
|
version_required = split_informed_dep[2]
|
||||||
exp_op = split_informed_dep[1] if split_informed_dep[1] != '=' else '=='
|
exp_op = split_informed_dep[1] if split_informed_dep[1] != '=' else '=='
|
||||||
|
|
||||||
if eval('dep_version {} version_required'.format(exp_op)):
|
if compare_versions(dep_version, exp_op, version_required):
|
||||||
aur_deps.add(dep_name)
|
aur_deps.add(dep_name)
|
||||||
missing_deps.add((dep_name, 'aur'))
|
missing_deps.add((dep_name, 'aur'))
|
||||||
except:
|
except:
|
||||||
@@ -334,20 +332,11 @@ class DependenciesAnalyser:
|
|||||||
version_found = [p for p in provided_map if p.startswith(version_pattern)]
|
version_found = [p for p in provided_map if p.startswith(version_pattern)]
|
||||||
|
|
||||||
if version_found:
|
if version_found:
|
||||||
version_found = clean_version(version_found[0].split('=')[1])
|
version_found = version_found[0].split('=')[1]
|
||||||
version_required = clean_version(dep_split[2])
|
version_required = dep_split[2]
|
||||||
|
op = dep_split[1] if dep_split[1] != '=' else '=='
|
||||||
|
|
||||||
try:
|
if not compare_versions(version_found, op, version_required):
|
||||||
version_found = parse_version(version_found)
|
|
||||||
version_required = parse_version(version_required)
|
|
||||||
|
|
||||||
op = dep_split[1] if dep_split[1] != '=' else '=='
|
|
||||||
match = eval('version_found {} version_required'.format(op))
|
|
||||||
except:
|
|
||||||
match = False
|
|
||||||
traceback.print_exc()
|
|
||||||
|
|
||||||
if not match:
|
|
||||||
self._fill_missing_dep(dep_name=dep_name, dep_exp=dep, aur_index=aur_index,
|
self._fill_missing_dep(dep_name=dep_name, dep_exp=dep, aur_index=aur_index,
|
||||||
missing_deps=missing_deps,
|
missing_deps=missing_deps,
|
||||||
remote_provided_map=remote_provided_map,
|
remote_provided_map=remote_provided_map,
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import traceback
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from colorama import Fore
|
|
||||||
from packaging.version import parse as parse_version
|
|
||||||
|
|
||||||
from bauh.api.abstract.model import PackageStatus
|
from bauh.api.abstract.model import PackageStatus
|
||||||
from bauh.api.http import HttpClient
|
from bauh.api.http import HttpClient
|
||||||
from bauh.gems.arch.model import ArchPackage
|
from bauh.gems.arch.model import ArchPackage
|
||||||
|
from bauh.gems.arch.version import compare_versions
|
||||||
from bauh.view.util.translation import I18n
|
from bauh.view.util.translation import I18n
|
||||||
|
|
||||||
URL_PKG_DOWNLOAD = 'https://aur.archlinux.org/{}'
|
URL_PKG_DOWNLOAD = 'https://aur.archlinux.org/{}'
|
||||||
@@ -64,26 +61,7 @@ class AURDataMapper:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def check_version_update(version: str, latest_version: str) -> bool:
|
def check_version_update(version: str, latest_version: str) -> bool:
|
||||||
if version and latest_version and version != latest_version:
|
if version and latest_version and version != latest_version:
|
||||||
try:
|
return compare_versions(latest_version, '>', version)
|
||||||
ver_epoch, latest_epoch = version.split(':'), latest_version.split(':')
|
|
||||||
|
|
||||||
if len(ver_epoch) > 1 and len(latest_epoch) > 1:
|
|
||||||
parsed_ver_epoch, parsed_latest_epoch = parse_version(ver_epoch[0]), parse_version(latest_epoch[0])
|
|
||||||
|
|
||||||
if parsed_ver_epoch == parsed_latest_epoch:
|
|
||||||
return parse_version(''.join(ver_epoch[1:])) < parse_version(''.join(latest_epoch[1:]))
|
|
||||||
else:
|
|
||||||
return parsed_ver_epoch < parsed_latest_epoch
|
|
||||||
elif len(ver_epoch) > 1 and len(latest_epoch) == 1:
|
|
||||||
return False
|
|
||||||
elif len(ver_epoch) == 1 and len(latest_epoch) > 1:
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return parse_version(version) < parse_version(latest_version)
|
|
||||||
except:
|
|
||||||
print('{}Version: {}. Latest version: {}{}'.format(Fore.RED, version, latest_version, Fore.RESET))
|
|
||||||
traceback.print_exc()
|
|
||||||
return False
|
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import traceback
|
|||||||
from threading import Thread
|
from threading import Thread
|
||||||
from typing import Dict, Set, List, Tuple, Iterable, Optional
|
from typing import Dict, Set, List, Tuple, Iterable, Optional
|
||||||
|
|
||||||
from packaging.version import parse as parse_version
|
|
||||||
|
|
||||||
from bauh.api.abstract.controller import UpgradeRequirements, UpgradeRequirement
|
from bauh.api.abstract.controller import UpgradeRequirements, UpgradeRequirement
|
||||||
from bauh.api.abstract.handler import ProcessWatcher
|
from bauh.api.abstract.handler import ProcessWatcher
|
||||||
from bauh.gems.arch import pacman, sorting
|
from bauh.gems.arch import pacman, sorting
|
||||||
@@ -14,6 +12,7 @@ from bauh.gems.arch.dependencies import DependenciesAnalyser
|
|||||||
from bauh.gems.arch.exceptions import PackageNotFoundException
|
from bauh.gems.arch.exceptions import PackageNotFoundException
|
||||||
from bauh.gems.arch.model import ArchPackage
|
from bauh.gems.arch.model import ArchPackage
|
||||||
from bauh.gems.arch.pacman import RE_DEP_OPERATORS
|
from bauh.gems.arch.pacman import RE_DEP_OPERATORS
|
||||||
|
from bauh.gems.arch.version import compare_versions
|
||||||
from bauh.view.util.translation import I18n
|
from bauh.view.util.translation import I18n
|
||||||
|
|
||||||
|
|
||||||
@@ -733,9 +732,7 @@ class UpdatesSummarizer:
|
|||||||
|
|
||||||
for v in versions:
|
for v in versions:
|
||||||
try:
|
try:
|
||||||
provided_version, required_version = parse_version(v), parse_version(dep_split[1])
|
if compare_versions(v, op, dep_split[1]):
|
||||||
|
|
||||||
if eval('provided_version {} required_version'.format(op)):
|
|
||||||
version_match = True
|
version_match = True
|
||||||
break
|
break
|
||||||
except:
|
except:
|
||||||
|
|||||||
35
bauh/gems/arch/version.py
Normal file
35
bauh/gems/arch/version.py
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from packaging.version import parse
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_version(version: str) -> Optional[str]:
|
||||||
|
if version:
|
||||||
|
final_version = version.strip()
|
||||||
|
|
||||||
|
if final_version:
|
||||||
|
if ':' not in final_version:
|
||||||
|
final_version = '0:{}'.format(final_version)
|
||||||
|
|
||||||
|
if '-' not in final_version:
|
||||||
|
final_version = '{}-1'.format(final_version)
|
||||||
|
|
||||||
|
return final_version
|
||||||
|
|
||||||
|
|
||||||
|
def compare_versions(version_a: str, operator: str, version_b: str) -> bool:
|
||||||
|
if operator:
|
||||||
|
a_obj, b_obj = parse(normalize_version(version_a)), parse(normalize_version(version_b))
|
||||||
|
|
||||||
|
if operator == '>':
|
||||||
|
return a_obj > b_obj
|
||||||
|
elif operator == '>=':
|
||||||
|
return a_obj >= b_obj
|
||||||
|
elif operator == '<':
|
||||||
|
return a_obj < b_obj
|
||||||
|
elif operator == '<=':
|
||||||
|
return a_obj <= b_obj
|
||||||
|
elif operator == '==':
|
||||||
|
return a_obj == b_obj
|
||||||
|
|
||||||
|
raise Exception("compare: invalid string operator {}".format(operator))
|
||||||
0
tests/common/__init__.py
Normal file
0
tests/common/__init__.py
Normal file
46
tests/gems/arch/test_version.py
Normal file
46
tests/gems/arch/test_version.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
from unittest import TestCase
|
||||||
|
|
||||||
|
from bauh.gems.arch import version
|
||||||
|
|
||||||
|
|
||||||
|
class CompareVersionsTest(TestCase):
|
||||||
|
|
||||||
|
def test_both_versions_only_filled_with_numbers_and_same_number_of_divisions(self):
|
||||||
|
self.assertFalse(version.compare_versions('1', '>', '2'))
|
||||||
|
self.assertTrue(version.compare_versions('1', '<', '2'))
|
||||||
|
self.assertTrue(version.compare_versions('1', '<=', '2'))
|
||||||
|
self.assertTrue(version.compare_versions('2', '>=', '1'))
|
||||||
|
self.assertTrue(version.compare_versions('1', '==', '1'))
|
||||||
|
self.assertFalse(version.compare_versions('1.1', '>', '2.0'))
|
||||||
|
self.assertTrue(version.compare_versions('1.1', '<', '2.0'))
|
||||||
|
self.assertTrue(version.compare_versions('1.1', '<=', '2.0'))
|
||||||
|
self.assertTrue(version.compare_versions('2.1', '>', '2.0'))
|
||||||
|
self.assertTrue(version.compare_versions('2.1', '>=', '2.0'))
|
||||||
|
self.assertTrue(version.compare_versions('2.0', '==', '2.0'))
|
||||||
|
|
||||||
|
def test_versions_only_filled_with_numbers_and_different_number_of_divisons(self):
|
||||||
|
self.assertFalse(version.compare_versions('1.0', '>', '2'))
|
||||||
|
self.assertTrue(version.compare_versions('1', '<', '2.0'))
|
||||||
|
self.assertTrue(version.compare_versions('1.1.1', '<=', '2'))
|
||||||
|
self.assertTrue(version.compare_versions('2', '>=', '1.0'))
|
||||||
|
self.assertTrue(version.compare_versions('1.0', '==', '1'))
|
||||||
|
self.assertTrue(version.compare_versions('1.1', '>', '1'))
|
||||||
|
self.assertFalse(version.compare_versions('1.1', '<', '1'))
|
||||||
|
|
||||||
|
def test_one_version_contain_mixed_letters_and_symbols(self):
|
||||||
|
self.assertTrue(version.compare_versions('2.3.3op2', '>=', '2.2.6'))
|
||||||
|
self.assertTrue(version.compare_versions('2.2a', '<', '2.2b'))
|
||||||
|
self.assertTrue(version.compare_versions('2.2a', '<', '2.3a'))
|
||||||
|
|
||||||
|
def test_versions_with_epochs(self):
|
||||||
|
self.assertTrue(version.compare_versions('1:1', '==', '1:1.0'))
|
||||||
|
self.assertTrue(version.compare_versions('1:1', '<', '1:1.1'))
|
||||||
|
self.assertTrue(version.compare_versions('1:1', '<=', '1:1.1'))
|
||||||
|
self.assertTrue(version.compare_versions('2:0', '>', '1:1.1'))
|
||||||
|
self.assertTrue(version.compare_versions('1:0', '>', '2.0-1'))
|
||||||
|
|
||||||
|
def test_versions_with_release_number(self):
|
||||||
|
self.assertTrue(version.compare_versions('1.0-1', '<', '1.0-2'))
|
||||||
|
self.assertTrue(version.compare_versions('1.0-2', '>', '1.0-1'))
|
||||||
|
self.assertTrue(version.compare_versions('1.0-1', '<', '1.0-10'))
|
||||||
|
self.assertTrue(version.compare_versions('1.0-10', '>', '1.0-1'))
|
||||||
Reference in New Issue
Block a user