[arch] fix -> regressions from commit db5eeabf

This commit is contained in:
Vinicius Moreira
2021-06-18 15:14:20 -03:00
parent 6e2a4222c8
commit c2493befda
6 changed files with 110 additions and 76 deletions

View File

@@ -7,7 +7,7 @@ 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.version import compare_versions
from bauh.gems.arch.version import match_required_version
from bauh.view.util.translation import I18n
@@ -229,7 +229,7 @@ class DependenciesAnalyser:
if len(split_dep) == 3 and split_dep[0] == dep_name:
version_provided = split_dep[2]
if compare_versions(version_provided, exp_op, version_required):
if match_required_version(version_provided, exp_op, version_required):
matched_providers.add(p)
break
@@ -275,9 +275,9 @@ class DependenciesAnalyser:
split_informed_dep = self.re_dep_operator.split(dep_exp)
try:
version_required = split_informed_dep[2]
exp_op = split_informed_dep[1] if split_informed_dep[1] != '=' else '=='
exp_op = split_informed_dep[1].strip()
if compare_versions(dep_version, exp_op, version_required):
if match_required_version(dep_version, exp_op, version_required):
aur_deps.add(dep_name)
missing_deps.add((dep_name, 'aur'))
except:
@@ -333,9 +333,9 @@ class DependenciesAnalyser:
if version_found:
version_found = version_found[0].split('=')[1]
version_required = dep_split[2]
op = dep_split[1] if dep_split[1] != '=' else '=='
op = dep_split[1].strip()
if not compare_versions(version_found, op, version_required):
if not match_required_version(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,

View File

@@ -5,7 +5,7 @@ from typing import Optional
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.gems.arch.version import normalize_version
from bauh.view.util.translation import I18n
URL_PKG_DOWNLOAD = 'https://aur.archlinux.org/{}'
@@ -61,7 +61,7 @@ class AURDataMapper:
@staticmethod
def check_version_update(version: str, latest_version: str) -> bool:
if version and latest_version and version != latest_version:
return compare_versions(latest_version, '>', version)
return normalize_version(latest_version) > normalize_version(version)
return False

View File

@@ -12,7 +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.gems.arch.version import match_required_version
from bauh.view.util.translation import I18n
@@ -725,14 +725,11 @@ class UpdatesSummarizer:
if versions:
op = ''.join(RE_DEP_OPERATORS.findall(dep))
if op == '=':
op = '=='
version_match = False
for v in versions:
try:
if compare_versions(v, op, dep_split[1]):
if match_required_version(current_version=v, operator=op, required_version=dep_split[1]):
version_match = True
break
except:

View File

@@ -1,35 +1,51 @@
from typing import Optional
import re
from packaging.version import parse
from packaging.version import LegacyVersion
RE_VERSION_WITH_RELEASE = re.compile(r'^(.+)-\d+$')
RE_VERSION_WITH_EPOCH = re.compile(r'^\d+:(.+)$')
def normalize_version(version: str) -> Optional[str]:
if version:
def normalize_version(version: str) -> LegacyVersion:
final_version = version.strip()
if final_version:
if ':' not in final_version:
if not RE_VERSION_WITH_EPOCH.match(final_version):
final_version = '0:{}'.format(final_version)
if '-' not in final_version:
if not RE_VERSION_WITH_RELEASE.match(final_version):
final_version = '{}-1'.format(final_version)
return final_version
return LegacyVersion(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))
def match_required_version(current_version: str, operator: str, required_version: str) -> bool:
final_required, final_current = required_version.strip(), current_version.strip()
if operator == '>':
return a_obj > b_obj
required_has_epoch, current_no_epoch = bool(RE_VERSION_WITH_EPOCH.match(final_required)), RE_VERSION_WITH_EPOCH.split(final_current)
current_has_epoch = len(current_no_epoch) > 1
if required_has_epoch and not current_has_epoch:
final_current = '0:{}'.format(final_current)
elif current_has_epoch and not required_has_epoch:
final_current = current_no_epoch[1]
required_has_release, current_no_release = bool(RE_VERSION_WITH_RELEASE.match(final_required)), RE_VERSION_WITH_RELEASE.split(final_current)
current_has_release = len(current_no_release) > 1
if required_has_release and not current_has_release:
final_current = '{}-1'.format(final_current)
elif current_has_release and not required_has_release:
final_current = current_no_release[1]
final_required, final_current = LegacyVersion(final_required), LegacyVersion(final_current)
if operator == '==' or operator == '=':
return final_current == final_required
elif operator == '>':
return final_current > final_required
elif operator == '>=':
return a_obj >= b_obj
return final_current >= final_required
elif operator == '<':
return a_obj < b_obj
return final_current < final_required
elif operator == '<=':
return a_obj <= b_obj
elif operator == '==':
return a_obj == b_obj
raise Exception("compare: invalid string operator {}".format(operator))
return final_current <= final_required

View File

@@ -10,7 +10,7 @@ class ArchDataMapperTest(TestCase):
@classmethod
def setUpClass(cls):
warnings.filterwarnings('ignore')
warnings.filterwarnings('ignore', category=DeprecationWarning)
def test_check_version_update(self):
self.assertTrue(AURDataMapper.check_version_update('1.0.0-1', '1.0.0-2'))
@@ -181,3 +181,17 @@ class ArchDataMapperTest(TestCase):
# in this case, install_date will be considered instead of package's last_modified.
# as 'install_date' is higher, only the string versions will be compared
self.assertTrue(mapper.check_update(pkg=pkg, last_modified=None))
def test_check_version_update__one_version_contain_mixed_letters_and_symbols(self):
self.assertTrue(AURDataMapper.check_version_update('2.2.6', '2.3.3op2'))
self.assertFalse(AURDataMapper.check_version_update('2.3', '2.2.a'))
self.assertTrue(AURDataMapper.check_version_update('2.2.a.123', '2.3'))
def test_check_update__only_installed_version_with_release_number(self):
self.assertTrue(AURDataMapper.check_version_update('2.2.6-1', '2.3'))
self.assertTrue(AURDataMapper.check_version_update('2.2', '2.2-2'))
self.assertFalse(AURDataMapper.check_version_update('2.2', '2.2-1'))
def test_check_update__versions_with_epoch(self):
self.assertTrue(AURDataMapper.check_version_update('2.3', '1:2.1'))
self.assertFalse(AURDataMapper.check_version_update('1:1.0', '2.1'))

View File

@@ -4,48 +4,55 @@ from unittest import TestCase
from bauh.gems.arch import version
class CompareVersionsTest(TestCase):
class MatchRequiredVersionTest(TestCase):
@classmethod
def setUpClass(cls):
warnings.filterwarnings('ignore')
warnings.filterwarnings('ignore', category=DeprecationWarning)
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_must_accept_single_or_both_equal_symbols_as_valid(self):
self.assertTrue(version.match_required_version('1', '=', '1'))
self.assertTrue(version.match_required_version('1', '==', '1'))
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_must_ignore_release_number_when_required_has_no_defined(self):
self.assertTrue(version.match_required_version('1.3.0-2', '==', '1.3.0'))
self.assertTrue(version.match_required_version('1.3.0-2', '<=', '1.3.0'))
self.assertTrue(version.match_required_version('1.3.0-2', '>=', '1.3.0'))
self.assertFalse(version.match_required_version('1.3.0-2', '<', '1.3.0'))
self.assertFalse(version.match_required_version('1.3.0-2', '>', '1.3.0'))
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_must_ignore_epoch_number_when_required_has_no_defined(self):
self.assertTrue(version.match_required_version('1:1.3.0-1', '>', '1.1.0'))
self.assertTrue(version.match_required_version('1:1.3.0-1', '>=', '1.1.0'))
self.assertFalse(version.match_required_version('1:1.3.0-1', '<', '1.1.0'))
self.assertFalse(version.match_required_version('1:1.3.0-1', '<=', '1.1.0'))
self.assertFalse(version.match_required_version('1:1.3.0-1', '==', '1.1.0'))
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_must_consider_default_epoch_for_current_version_when_required_has_epoch(self):
self.assertFalse(version.match_required_version('1.1.0', '==', '1:1.1.0')) # 1.1.0 -> 0:1.1.0
self.assertFalse(version.match_required_version('1.1.0', '>', '1:1.1.0')) # 1.1.0 -> 0:1.1.0
self.assertFalse(version.match_required_version('1.1.0', '>=', '1:1.1.0')) # 1.1.0 -> 0:1.1.0
self.assertTrue(version.match_required_version('1.1.0', '<', '1:1.1.0')) # 1.1.0 -> 0:1.1.0
self.assertTrue(version.match_required_version('1.1.0', '<=', '1:1.1.0')) # 1.1.0 -> 0:1.1.0
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'))
self.assertTrue(version.match_required_version('1.1.0', '==', '0:1.1.0')) # 1.1.0 -> 0:1.1.0
def test_must_match_when_current_version_is_composed_of_alphanumerics_but_required_no(self):
self.assertTrue(version.match_required_version('2.3.3op2', '>', '2.2.6'))
self.assertTrue(version.match_required_version('2.3.3op2', '>=', '2.2.6'))
self.assertFalse(version.match_required_version('2.3.3op2', '==', '2.2.6'))
self.assertFalse(version.match_required_version('2.3.3op2', '<', '2.2.6'))
self.assertFalse(version.match_required_version('2.3.3op2', '<=', '2.2.6'))
# opposite comparisons
self.assertFalse(version.match_required_version('2.2.6', '>', '2.3.3op2'))
self.assertFalse(version.match_required_version('2.2.6', '>=', '2.3.3op2'))
self.assertFalse(version.match_required_version('2.2.6', '==', '2.3.3op2'))
self.assertTrue(version.match_required_version('2.2.6', '<', '2.3.3op2'))
self.assertTrue(version.match_required_version('2.2.6', '<=', '2.3.3op2'))
def test_must_match_when_both_versions_are_composed_of_alphanumerics(self):
self.assertTrue(version.match_required_version('2.3.3ab', '==', '2.3.3ab'))
self.assertTrue(version.match_required_version('2.3.3ab', '<', '2.3.3ac'))
self.assertTrue(version.match_required_version('2.3.3ad', '>', '2.3.3ac'))
self.assertTrue(version.match_required_version('2.3.3ad', '<', '2.3.3ad.1'))