diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cb619db..d54e10d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,10 @@ 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.6.1] +## [0.6.1] 2019-09- ### Improvements: - Better warning presentation when there are several messages +- Better AUR update check handling - "Show" button available for all information fields ### Fixes: diff --git a/bauh/gems/arch/mapper.py b/bauh/gems/arch/mapper.py index cdaa1828..72db9469 100644 --- a/bauh/gems/arch/mapper.py +++ b/bauh/gems/arch/mapper.py @@ -1,3 +1,4 @@ +import re from datetime import datetime from bauh.api.abstract.model import PackageStatus @@ -5,6 +6,16 @@ from bauh.api.http import HttpClient from bauh.gems.arch.model import ArchPackage URL_PKG_DOWNLOAD = 'https://aur.archlinux.org/{}' +RE_LETTERS = re.compile(r'\.([a-zA-Z]+)-\d+$') + +RE_SFX = ('r', 're', 'release') +GA_SFX = ('ga', 'ge') +RC_SFX = ('rc',) +BETA_SFX = ('b', 'beta') +AL_SFX = ('alpha', 'alfa') +DEV_SFX = ('dev', 'devel', 'development') + +V_SUFFIX_MAP = {s: {'c': sfxs[0], 'p': idx} for idx, sfxs in enumerate([RE_SFX, GA_SFX, RC_SFX, BETA_SFX, AL_SFX, DEV_SFX]) for s in sfxs} class ArchDataMapper: @@ -36,7 +47,36 @@ class ArchDataMapper: pkg.url_download = URL_PKG_DOWNLOAD.format(package['URLPath']) if package.get('URLPath') else None pkg.first_submitted = datetime.fromtimestamp(package['FirstSubmitted']) if package.get('FirstSubmitted') else None pkg.last_modified = datetime.fromtimestamp(package['LastModified']) if package.get('LastModified') else None - pkg.update = pkg.version and pkg.latest_version and pkg.latest_version > pkg.version + pkg.update = self.check_update(pkg.version, pkg.latest_version) + + @staticmethod + def check_update(version: str, latest_version: str) -> bool: + if version and latest_version: + current_sfx = RE_LETTERS.findall(version) + latest_sf = RE_LETTERS.findall(latest_version) + + if latest_sf and current_sfx: + current_sfx = current_sfx[0] + latest_sf = latest_sf[0] + + current_sfx_data = V_SUFFIX_MAP.get(current_sfx.lower()) + latest_sfx_data = V_SUFFIX_MAP.get(latest_sf.lower()) + + if current_sfx_data and latest_sfx_data: + nversion = version.split(current_sfx)[0] + nlatest = latest_version.split(latest_sf)[0] + + if nversion == nlatest: + if current_sfx_data['c'] != latest_sfx_data['c']: + return latest_sfx_data['p'] < current_sfx_data['p'] + else: + return ''.join(latest_version.split(latest_sf)) > ''.join(version.split(current_sfx)) + + return nlatest > nversion + + return latest_version > version + + return False def fill_package_build(self, pkg: ArchPackage): res = self.http_client.get(pkg.get_pkg_build_url()) diff --git a/setup.py b/setup.py index 1fa96690..a0de0e07 100644 --- a/setup.py +++ b/setup.py @@ -30,9 +30,10 @@ setup( author_email=AUTHOR_EMAIL, python_requires=">=3.5", url=URL, - packages=find_packages(), + packages=find_packages(exclude=["tests.*", "tests"]), package_data={NAME: ["view/resources/locale/*", "view/resources/img/*", "gems/*/resources/img/*", "gems/*/resources/locale/*"]}, install_requires=requirements, + test_suite="tests", entry_points={ "console_scripts": [ "{name}={name}.app:main".format(name=NAME) diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/gems/__init__.py b/tests/gems/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/gems/arch/__init__.py b/tests/gems/arch/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/gems/arch/arch_data_mapper_test.py b/tests/gems/arch/arch_data_mapper_test.py new file mode 100644 index 00000000..218894a6 --- /dev/null +++ b/tests/gems/arch/arch_data_mapper_test.py @@ -0,0 +1,175 @@ +from unittest import TestCase + +from bauh.gems.arch.mapper import ArchDataMapper + + +class ArchDataMapperTest(TestCase): + + def test_check_update_no_suffix(self): + self.assertTrue(ArchDataMapper.check_update('1.0.0-1', '1.0.0-2')) + self.assertFalse(ArchDataMapper.check_update('1.0.0-2', '1.0.0-1')) + self.assertTrue(ArchDataMapper.check_update('1.0.0-5', '1.0.1-1')) + self.assertFalse(ArchDataMapper.check_update('1.0.1-1', '1.0.0-1')) + self.assertTrue(ArchDataMapper.check_update('1.0.5-5', '1.1.0-2')) + self.assertFalse(ArchDataMapper.check_update('1.1.0-2', '1.0.5-5')) + self.assertTrue(ArchDataMapper.check_update('1.5.0-2', '1.5.1-1')) + self.assertFalse(ArchDataMapper.check_update('1.5.1-1', '1.5.0-2')) + self.assertTrue(ArchDataMapper.check_update('1.5.1-1', '1.5.1-2')) + self.assertTrue(ArchDataMapper.check_update('1.5.1-1', '2.0.0-1')) + self.assertFalse(ArchDataMapper.check_update('2.0.0-1', '1.5.1-1')) + + def test_check_update_release(self): + # RE + self.assertTrue(ArchDataMapper.check_update('1.0.0.R-1', '1.0.0.R-2')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.R-2', '1.0.0.R-1')) + self.assertFalse(ArchDataMapper.check_update('1.0.1.R-1', '1.0.0.R-5')) + self.assertTrue(ArchDataMapper.check_update('1.0.1.R-1', '1.0.1.R-2')) + self.assertFalse(ArchDataMapper.check_update('1.0.2.R-1', '1.0.1.R-7')) + + self.assertTrue(ArchDataMapper.check_update('1.0.0.RE-1', '1.0.0.R-2')) + self.assertTrue(ArchDataMapper.check_update('1.0.0.RELEASE-2', '1.0.0.R-5')) + self.assertFalse(ArchDataMapper.check_update('1.0.1.R-1', '1.0.0.RELEASE-5')) + self.assertFalse(ArchDataMapper.check_update('1.0.1.R-1', '1.0.0.RE-1')) + + # GA + self.assertFalse(ArchDataMapper.check_update('1.0.0.R-1', '1.0.0.Ge-1')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.RE-1', '1.0.0.GA-1')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.RELEASE-1', '1.0.0.Ge-1')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.R-1', '1.0.0.GE-1')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.RE-1', '1.0.0.GE-1')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.RELEASE-1', '1.0.0.GE-1')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.R-1', '1.0.0.GA-1')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.RE-1', '1.0.0.GA-1')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.RELEASE-1', '1.0.0.GA-1')) + + self.assertTrue(ArchDataMapper.check_update('1.0.0.R-5', '1.0.1.GA-1')) + + # RCS + self.assertFalse(ArchDataMapper.check_update('1.0.0.R-1', '1.0.0.RC-1')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.RE-1', '1.0.0.RC-1')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.RELEASE-1', '1.0.0.RC-1')) + + self.assertTrue(ArchDataMapper.check_update('1.0.0.R-5', '1.0.1.RC-1')) + + # BETA + self.assertFalse(ArchDataMapper.check_update('1.0.0.R-1', '1.0.0.B-2')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.RE-1', '1.0.0.B-2')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.RELEASE-1', '1.0.0.B-2')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.R-1', '1.0.0.BETA-2')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.RE-1', '1.0.0.BETA-2')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.RELEASE-1', '1.0.0.BETA-2')) + + self.assertTrue(ArchDataMapper.check_update('1.0.0.R-5', '1.0.1.BETA-1')) + + # ALPHA + self.assertFalse(ArchDataMapper.check_update('1.0.0.R-1', '1.0.0.Alpha-2')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.RE-1', '1.0.0.ALPHA-2')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.RELEASE-1', '1.0.0.ALPHA-2')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.R-1', '1.0.0.ALPHA-2')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.RE-1', '1.0.0.ALPHA-2')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.RELEASE-1', '1.0.0.ALPHA-2')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.R-1', '1.0.0.ALFA-2')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.RE-1', '1.0.0.ALFA-2')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.RELEASE-1', '1.0.0.ALFA-2')) + + self.assertTrue(ArchDataMapper.check_update('1.0.0.R-5', '1.0.1.Alfa-1')) + + # DEV + self.assertFalse(ArchDataMapper.check_update('1.0.0.R-1', '1.0.0.DeV-2')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.RE-1', '1.0.0.DEV-2')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.RELEASE-1', '1.0.0.DEVEL-2')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.R-1', '1.0.0.DEV-2')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.RE-1', '1.0.0.DEV-2')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.RELEASE-1', '1.0.0.DEV-2')) + + self.assertTrue(ArchDataMapper.check_update('1.0.0.R-5', '1.0.1.DEV-1')) + + def test_check_update_ga(self): + # GA + self.assertFalse(ArchDataMapper.check_update('1.0.0.GA-1', '1.0.0.GE-1')) + self.assertTrue(ArchDataMapper.check_update('1.0.0.GE-1', '1.0.0.GA-2')) + self.assertTrue(ArchDataMapper.check_update('1.0.0.GA-2', '1.0.1.GA-1')) + self.assertFalse(ArchDataMapper.check_update('1.1.0.GE-3', '1.0.6.GE-10')) + + # RC + self.assertFalse(ArchDataMapper.check_update('1.0.0.GA-1', '1.0.0.RC-1')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.GE-1', '1.0.0.RC-1')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.GA-1', '1.0.0.RC-1')) + + self.assertTrue(ArchDataMapper.check_update('1.0.0.GE-1', '1.0.1.RC-1')) + self.assertTrue(ArchDataMapper.check_update('1.0.10.GA-10', '1.1.0.RC-1')) + self.assertFalse(ArchDataMapper.check_update('1.1.0.GE-1', '1.0.1.RC-1')) + + # BETA + self.assertFalse(ArchDataMapper.check_update('1.0.0.GA-1', '1.0.0.BETA-1')) + self.assertTrue(ArchDataMapper.check_update('1.0.0.GE-1', '1.0.1.BETA-1')) + + # ALPHA + self.assertFalse(ArchDataMapper.check_update('1.0.0.GE-1', '1.0.0.ALPHA-1')) + self.assertTrue(ArchDataMapper.check_update('1.0.0.GA-1', '1.0.1.ALPHA-1')) + + # DEV + self.assertFalse(ArchDataMapper.check_update('1.0.0.GA-1', '1.0.0.DEV-1')) + self.assertTrue(ArchDataMapper.check_update('1.0.0.GE-1', '1.0.1.DEV-1')) + + def test_check_update_rc(self): + # RC + self.assertFalse(ArchDataMapper.check_update('1.0.0.RC-1', '1.0.0.RC-1')) + self.assertTrue(ArchDataMapper.check_update('1.0.0.RC-1', '1.0.0.RC-2')) + self.assertTrue(ArchDataMapper.check_update('1.0.0.RC-2', '1.0.1.RC-1')) + self.assertFalse(ArchDataMapper.check_update('1.1.0.RC-3', '1.0.6.RC-10')) + + # BETA + self.assertFalse(ArchDataMapper.check_update('1.0.0.RC-1', '1.0.0.BETA-1')) + self.assertTrue(ArchDataMapper.check_update('1.0.0.RC-1', '1.0.1.BETA-1')) + + # ALPHA + self.assertFalse(ArchDataMapper.check_update('1.0.0.RC-1', '1.0.0.ALPHA-1')) + self.assertTrue(ArchDataMapper.check_update('1.0.0.RC-1', '1.0.1.ALPHA-1')) + + # DEV + self.assertFalse(ArchDataMapper.check_update('1.0.0.RC-1', '1.0.0.DEV-1')) + self.assertTrue(ArchDataMapper.check_update('1.0.0.RC-1', '1.0.1.DEV-1')) + + def test_check_update_beta(self): + # BETA + self.assertFalse(ArchDataMapper.check_update('1.0.0.BETA-1', '1.0.0.BETA-1')) + self.assertTrue(ArchDataMapper.check_update('1.0.0.BETA-1', '1.0.0.BETA-2')) + self.assertTrue(ArchDataMapper.check_update('1.0.0.BETA-2', '1.0.1.B-1')) + self.assertFalse(ArchDataMapper.check_update('1.1.0.B-3', '1.0.6.BETA-10')) + + # ALPHA + self.assertFalse(ArchDataMapper.check_update('1.0.0.BETA-1', '1.0.0.ALPHA-1')) + self.assertTrue(ArchDataMapper.check_update('1.0.0.B-1', '1.0.1.ALPHA-1')) + + # DEV + self.assertFalse(ArchDataMapper.check_update('1.0.0.BETA-1', '1.0.0.DEV-1')) + self.assertTrue(ArchDataMapper.check_update('1.0.0.B-1', '1.0.1.DEV-1')) + + def test_check_update_alpha(self): + # ALPHA + self.assertFalse(ArchDataMapper.check_update('1.0.0.ALPHA-1', '1.0.0.ALPHA-1')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.ALPHA-1', '1.0.0.ALFA-1')) + self.assertTrue(ArchDataMapper.check_update('1.0.0.ALFA-1', '1.0.0.ALPHA-2')) + self.assertTrue(ArchDataMapper.check_update('1.0.0.ALPHA-2', '1.0.1.ALFA-1')) + self.assertFalse(ArchDataMapper.check_update('1.1.0.ALFA-3', '1.0.6.ALFA-10')) + + # DEV + self.assertFalse(ArchDataMapper.check_update('1.0.0.ALFA-1', '1.0.0.DEV-1')) + self.assertTrue(ArchDataMapper.check_update('1.0.0.ALPHA-1', '1.0.1.DEV-1')) + + def test_check_update_dev(self): + self.assertFalse(ArchDataMapper.check_update('1.0.0.DEV-1', '1.0.0.DEV-1')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.DEV-1', '1.0.0.DEVEL-1')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.DEVEL-1', '1.0.0.DEVELOPMENT-1')) + self.assertTrue(ArchDataMapper.check_update('1.0.0.DEV-1', '1.0.0.DEVEL-2')) + self.assertTrue(ArchDataMapper.check_update('1.0.0.DEVEL-2', '1.0.1.DEV-1')) + self.assertFalse(ArchDataMapper.check_update('1.1.0.DEV-3', '1.0.6.DEVELOPMENT-10')) + + def test_check_update_unknown_suffix(self): + self.assertTrue(ArchDataMapper.check_update('1.0.0.BALL-1', '1.0.0.TAR-1')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.TAR-1', '1.0.0.BALL-1')) + + def test_check_update_known_and_unknown_suffix(self): + self.assertTrue(ArchDataMapper.check_update('1.0.0.RE-1', '1.0.0.TAR-1')) + self.assertFalse(ArchDataMapper.check_update('1.0.0.TAR-1', '1.0.0.RE-1'))