mirror of
https://github.com/spalencsar/bearhub.git
synced 2026-07-07 00:04: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/).
|
||||
|
||||
## [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
|
||||
### Improvements
|
||||
- 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'
|
||||
|
||||
import os
|
||||
|
||||
@@ -3,13 +3,11 @@ import traceback
|
||||
from threading import Thread
|
||||
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.gems.arch import pacman, message, sorting, confirmation
|
||||
from bauh.gems.arch.aur import AURClient
|
||||
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
|
||||
|
||||
|
||||
@@ -220,7 +218,7 @@ class DependenciesAnalyser:
|
||||
matched_providers = set()
|
||||
split_informed_dep = self.re_dep_operator.split(dep_exp)
|
||||
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 '=='
|
||||
|
||||
for p in providers:
|
||||
@@ -230,9 +228,9 @@ class DependenciesAnalyser:
|
||||
split_dep = self.re_dep_operator.split(provided_exp)
|
||||
|
||||
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)
|
||||
break
|
||||
|
||||
@@ -270,17 +268,17 @@ class DependenciesAnalyser:
|
||||
self.__raise_dependency_not_found(dep_exp, watcher)
|
||||
else:
|
||||
try:
|
||||
dep_version = parse_version(clean_version(dep_info[0]['Version']))
|
||||
dep_version = dep_info[0]['Version']
|
||||
except:
|
||||
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)
|
||||
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 '=='
|
||||
|
||||
if eval('dep_version {} version_required'.format(exp_op)):
|
||||
if compare_versions(dep_version, exp_op, version_required):
|
||||
aur_deps.add(dep_name)
|
||||
missing_deps.add((dep_name, 'aur'))
|
||||
except:
|
||||
@@ -334,20 +332,11 @@ class DependenciesAnalyser:
|
||||
version_found = [p for p in provided_map if p.startswith(version_pattern)]
|
||||
|
||||
if version_found:
|
||||
version_found = clean_version(version_found[0].split('=')[1])
|
||||
version_required = clean_version(dep_split[2])
|
||||
|
||||
try:
|
||||
version_found = parse_version(version_found)
|
||||
version_required = parse_version(version_required)
|
||||
|
||||
version_found = version_found[0].split('=')[1]
|
||||
version_required = dep_split[2]
|
||||
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:
|
||||
if not compare_versions(version_found, op, version_required):
|
||||
self._fill_missing_dep(dep_name=dep_name, dep_exp=dep, aur_index=aur_index,
|
||||
missing_deps=missing_deps,
|
||||
remote_provided_map=remote_provided_map,
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
import logging
|
||||
import os
|
||||
import traceback
|
||||
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.http import HttpClient
|
||||
from bauh.gems.arch.model import ArchPackage
|
||||
from bauh.gems.arch.version import compare_versions
|
||||
from bauh.view.util.translation import I18n
|
||||
|
||||
URL_PKG_DOWNLOAD = 'https://aur.archlinux.org/{}'
|
||||
@@ -64,26 +61,7 @@ class AURDataMapper:
|
||||
@staticmethod
|
||||
def check_version_update(version: str, latest_version: str) -> bool:
|
||||
if version and latest_version and version != latest_version:
|
||||
try:
|
||||
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 compare_versions(latest_version, '>', version)
|
||||
|
||||
return False
|
||||
|
||||
|
||||
@@ -4,8 +4,6 @@ import traceback
|
||||
from threading import Thread
|
||||
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.handler import ProcessWatcher
|
||||
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.model import ArchPackage
|
||||
from bauh.gems.arch.pacman import RE_DEP_OPERATORS
|
||||
from bauh.gems.arch.version import compare_versions
|
||||
from bauh.view.util.translation import I18n
|
||||
|
||||
|
||||
@@ -733,9 +732,7 @@ class UpdatesSummarizer:
|
||||
|
||||
for v in versions:
|
||||
try:
|
||||
provided_version, required_version = parse_version(v), parse_version(dep_split[1])
|
||||
|
||||
if eval('provided_version {} required_version'.format(op)):
|
||||
if compare_versions(v, op, dep_split[1]):
|
||||
version_match = True
|
||||
break
|
||||
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