mirror of
https://github.com/spalencsar/bearhub.git
synced 2026-07-06 21:44:16 +02:00
[arch] improvement -> AUR: upgrade checking now considers modification dates as well
This commit is contained in:
@@ -5,14 +5,19 @@ 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.11]
|
||||
### New system requirements
|
||||
- **python-dateutil**: better Python library for date handling (install the equivalent package for your Linux distribution before upgrading bauh)
|
||||
|
||||
### Improvements
|
||||
- Arch
|
||||
- AUR: upgrade checking now considers modification dates as well (needed because not all AUR packages follow versioning standards)
|
||||
- the task responsible for generating a local AUR index is displayed on the initialization dialog
|
||||
|
||||
### Fixes
|
||||
- AppImage
|
||||
- some installed applications cannot be launched by their desktop entries (regression from **0.9.10**) [#155](https://github.com/vinifmor/bauh/issues/155). If any of your installed AppImages are affected by this issue, just reinstall them.
|
||||
|
||||
|
||||
## [0.9.10] 2020-12-11
|
||||
### Features
|
||||
- Web
|
||||
|
||||
@@ -31,9 +31,10 @@ To contribute have a look at [CONTRIBUTING.md](https://github.com/vinifmor/bauh/
|
||||
#### Debian-based distros
|
||||
- **python3.5** or above
|
||||
- **pip3**
|
||||
- **python3-requests**
|
||||
- **python-yaml**
|
||||
- **python3-dateutil**
|
||||
- **python3-pyqt5.qtsvg**
|
||||
- **python3-requests**
|
||||
- **libqt5svg5**
|
||||
- **qt5dxcb-plugin**
|
||||
- **libappindicator3** (for the **tray mode** in GTK3 desktop environments)
|
||||
@@ -42,6 +43,7 @@ To contribute have a look at [CONTRIBUTING.md](https://github.com/vinifmor/bauh/
|
||||
|
||||
#### Arch-based distros
|
||||
- **python**
|
||||
- **python-dateutil**
|
||||
- **python-requests**
|
||||
- **python-pip**
|
||||
- **python-pyqt5**
|
||||
|
||||
@@ -19,11 +19,12 @@ class DiskCacheLoader:
|
||||
"""
|
||||
pass
|
||||
|
||||
def fill(self, pkg: SoftwarePackage):
|
||||
def fill(self, pkg: SoftwarePackage, sync: bool = False):
|
||||
"""
|
||||
fill cached data from the disk of a given package instance
|
||||
If a cache mapping was previously done, then data retrieved will be cached to memory as well.
|
||||
:param pkg:
|
||||
:param sync: if the package data must be filled synchronously
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
@@ -4,7 +4,7 @@ import sys
|
||||
import time
|
||||
from io import StringIO
|
||||
from subprocess import PIPE
|
||||
from typing import List, Tuple, Set, Dict
|
||||
from typing import List, Tuple, Set, Dict, Optional
|
||||
|
||||
# default environment variables for subprocesses.
|
||||
from bauh.api.abstract.handler import ProcessWatcher
|
||||
@@ -322,6 +322,11 @@ def check_enabled_services(*names: str) -> Dict[str, bool]:
|
||||
return {s: status[i].strip().lower() == 'enabled' for i, s in enumerate(names) if s}
|
||||
|
||||
|
||||
def execute(cmd: str, shell: bool = False) -> Tuple[int, str]:
|
||||
p = subprocess.run(args=cmd.split(' ') if not shell else [cmd], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=shell)
|
||||
def execute(cmd: str, shell: bool = False, cwd: Optional[str] = None) -> Tuple[int, str]:
|
||||
p = subprocess.run(args=cmd.split(' ') if not shell else [cmd],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
shell=shell,
|
||||
cwd=cwd)
|
||||
|
||||
return p.returncode, p.stdout.decode()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import collections
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
def deep_update(source: dict, overrides: dict):
|
||||
@@ -26,3 +26,7 @@ def size_to_byte(size: float, unit: str) -> int:
|
||||
final_size = size * 1000000000000000
|
||||
|
||||
return int(final_size)
|
||||
|
||||
|
||||
def datetime_as_milis(date: datetime) -> int:
|
||||
return int(round(date.timestamp() * 1000))
|
||||
|
||||
@@ -14,6 +14,7 @@ from threading import Thread
|
||||
from typing import List, Set, Type, Tuple, Dict, Iterable, Optional
|
||||
|
||||
import requests
|
||||
from dateutil.parser import parse as parse_date
|
||||
|
||||
from bauh.api.abstract.controller import SearchResult, SoftwareManager, ApplicationContext, UpgradeRequirements, \
|
||||
TransactionResult, SoftwareAction
|
||||
@@ -30,6 +31,7 @@ from bauh.commons.category import CategoriesDownloader
|
||||
from bauh.commons.config import save_config
|
||||
from bauh.commons.html import bold
|
||||
from bauh.commons.system import SystemProcess, ProcessHandler, new_subprocess, run_cmd, SimpleProcess
|
||||
from bauh.commons.util import datetime_as_milis
|
||||
from bauh.commons.view_utils import new_select
|
||||
from bauh.gems.arch import aur, pacman, makepkg, message, confirmation, disk, git, \
|
||||
gpg, URL_CATEGORIES_FILE, CATEGORIES_FILE_PATH, CUSTOM_MAKEPKG_FILE, SUGGESTIONS_FILE, \
|
||||
@@ -40,7 +42,7 @@ from bauh.gems.arch.config import read_config, get_build_dir
|
||||
from bauh.gems.arch.dependencies import DependenciesAnalyser
|
||||
from bauh.gems.arch.download import MultithreadedDownloadService, ArchDownloadException
|
||||
from bauh.gems.arch.exceptions import PackageNotFoundException, PackageInHoldException
|
||||
from bauh.gems.arch.mapper import ArchDataMapper
|
||||
from bauh.gems.arch.mapper import AURDataMapper
|
||||
from bauh.gems.arch.model import ArchPackage
|
||||
from bauh.gems.arch.output import TransactionStatusHandler
|
||||
from bauh.gems.arch.pacman import RE_DEP_OPERATORS
|
||||
@@ -73,7 +75,7 @@ class TransactionContext:
|
||||
missing_deps: List[Tuple[str, str]] = None, installed: Set[str] = None, removed: Dict[str, SoftwarePackage] = None,
|
||||
disk_loader: DiskCacheLoader = None, disk_cache_updater: Thread = None,
|
||||
new_pkg: bool = False, custom_pkgbuild_path: str = None,
|
||||
pkgs_to_build: Set[str] = None):
|
||||
pkgs_to_build: Set[str] = None, last_modified: Optional[int] = None):
|
||||
self.name = name
|
||||
self.base = base
|
||||
self.maintainer = maintainer
|
||||
@@ -103,13 +105,14 @@ class TransactionContext:
|
||||
self.custom_pkgbuild_path = custom_pkgbuild_path
|
||||
self.pkgs_to_build = pkgs_to_build
|
||||
self.previous_change_progress = change_progress
|
||||
self.last_modified = last_modified
|
||||
|
||||
@classmethod
|
||||
def gen_context_from(cls, pkg: ArchPackage, arch_config: dict, root_password: str, handler: ProcessHandler) -> "TransactionContext":
|
||||
return cls(name=pkg.name, base=pkg.get_base_name(), maintainer=pkg.maintainer, repository=pkg.repository,
|
||||
arch_config=arch_config, watcher=handler.watcher, handler=handler, skip_opt_deps=True,
|
||||
change_progress=True, root_password=root_password, dependency=False,
|
||||
installed=set(), removed={}, new_pkg=not pkg.installed)
|
||||
installed=set(), removed={}, new_pkg=not pkg.installed, last_modified=pkg.last_modified)
|
||||
|
||||
def get_base_name(self):
|
||||
return self.base if self.base else self.name
|
||||
@@ -189,7 +192,7 @@ class ArchManager(SoftwareManager):
|
||||
self.aur_cache = context.cache_factory.new()
|
||||
# context.disk_loader_factory.map(ArchPackage, self.aur_cache) TODO
|
||||
|
||||
self.mapper = ArchDataMapper(http_client=context.http_client, i18n=context.i18n)
|
||||
self.aur_mapper = AURDataMapper(http_client=context.http_client, i18n=context.i18n, logger=context.logger)
|
||||
self.i18n = context.i18n
|
||||
self.aur_client = AURClient(http_client=context.http_client, logger=context.logger, x86_64=context.is_system_x86_64())
|
||||
self.dcache_updater = None
|
||||
@@ -334,7 +337,7 @@ class ArchManager(SoftwareManager):
|
||||
pkg = installed_pkgs.get(apidata['Name'])
|
||||
|
||||
if not pkg:
|
||||
pkg = self.mapper.map_api_data(apidata, None, self.categories)
|
||||
pkg = self.aur_mapper.map_api_data(apidata, None, self.categories)
|
||||
pkg.downgrade_enabled = downgrade_enabled
|
||||
|
||||
if pkg.installed:
|
||||
@@ -342,7 +345,7 @@ class ArchManager(SoftwareManager):
|
||||
else:
|
||||
res.new.append(pkg)
|
||||
|
||||
Thread(target=self.mapper.fill_package_build, args=(pkg,), daemon=True).start()
|
||||
Thread(target=self.aur_mapper.fill_package_build, args=(pkg,), daemon=True).start()
|
||||
|
||||
def _search_in_repos_and_fill(self, words: str, disk_loader: DiskCacheLoader, read_installed: Thread, installed: List[ArchPackage], res: SearchResult):
|
||||
repo_search = pacman.search(words)
|
||||
@@ -383,7 +386,7 @@ class ArchManager(SoftwareManager):
|
||||
read_installed.join()
|
||||
aur_installed = {p.name: p for p in installed if p.repository == 'aur'}
|
||||
|
||||
downgrade_enabled = git.is_enabled()
|
||||
downgrade_enabled = git.is_installed()
|
||||
for pkgdata in api_res['results']:
|
||||
self._upgrade_search_result(pkgdata, aur_installed, downgrade_enabled, res, disk_loader)
|
||||
|
||||
@@ -407,7 +410,7 @@ class ArchManager(SoftwareManager):
|
||||
if pkgsinfo:
|
||||
read_installed.join()
|
||||
aur_installed = {p.name: p for p in installed if p.repository == 'aur'}
|
||||
downgrade_enabled = git.is_enabled()
|
||||
downgrade_enabled = git.is_installed()
|
||||
|
||||
for pkgdata in pkgsinfo:
|
||||
self._upgrade_search_result(pkgdata, aur_installed, downgrade_enabled, res, disk_loader)
|
||||
@@ -452,7 +455,7 @@ class ArchManager(SoftwareManager):
|
||||
|
||||
def _fill_aur_pkgs(self, aur_pkgs: dict, output: List[ArchPackage], disk_loader: DiskCacheLoader, internet_available: bool,
|
||||
arch_config: dict):
|
||||
downgrade_enabled = git.is_enabled()
|
||||
downgrade_enabled = git.is_installed()
|
||||
|
||||
if internet_available:
|
||||
try:
|
||||
@@ -461,14 +464,18 @@ class ArchManager(SoftwareManager):
|
||||
if pkgsinfo:
|
||||
editable_pkgbuilds = self._read_editable_pkgbuilds() if arch_config['edit_aur_pkgbuild'] is not False else None
|
||||
for pkgdata in pkgsinfo:
|
||||
pkg = self.mapper.map_api_data(pkgdata, aur_pkgs, self.categories)
|
||||
pkg = self.aur_mapper.map_api_data(pkgdata, aur_pkgs, self.categories)
|
||||
pkg.downgrade_enabled = downgrade_enabled
|
||||
pkg.pkgbuild_editable = pkg.name in editable_pkgbuilds if editable_pkgbuilds is not None else None
|
||||
|
||||
if pkg.installed:
|
||||
if disk_loader:
|
||||
disk_loader.fill(pkg)
|
||||
pkg.status = PackageStatus.READY
|
||||
disk_loader.fill(pkg, sync=True)
|
||||
|
||||
pkg.update = self._check_aur_package_update(pkg=pkg,
|
||||
installed_data=aur_pkgs.get(pkg.name, {}),
|
||||
api_data=pkgdata)
|
||||
pkg.status = PackageStatus.READY
|
||||
output.append(pkg)
|
||||
|
||||
return
|
||||
@@ -489,10 +496,24 @@ class ArchManager(SoftwareManager):
|
||||
|
||||
if disk_loader:
|
||||
disk_loader.fill(pkg)
|
||||
pkg.status = PackageStatus.READY
|
||||
|
||||
pkg.status = PackageStatus.READY
|
||||
output.append(pkg)
|
||||
|
||||
def _check_aur_package_update(self, pkg: ArchPackage, installed_data: dict, api_data: dict) -> bool:
|
||||
if pkg.last_modified is None: # if last_modified is not available, then the install_date will be used instead
|
||||
install_date = installed_data.get('install_date')
|
||||
|
||||
if install_date:
|
||||
try:
|
||||
pkg.install_date = datetime_as_milis(parse_date(install_date))
|
||||
except ValueError:
|
||||
self.logger.error("Could not parse 'install_date' ({}) from AUR package '{}'".format(install_date, pkg.name))
|
||||
else:
|
||||
self.logger.error("AUR package '{}' install_date was not retrieved".format(pkg.name))
|
||||
|
||||
return self.aur_mapper.check_update(pkg=pkg, last_modified=api_data['LastModified'])
|
||||
|
||||
def _fill_repo_updates(self, updates: dict):
|
||||
updates.update(pacman.list_repository_updates())
|
||||
|
||||
@@ -620,18 +641,21 @@ class ArchManager(SoftwareManager):
|
||||
context.project_dir = clone_path
|
||||
srcinfo_path = '{}/.SRCINFO'.format(clone_path)
|
||||
|
||||
commits = run_cmd("git log", cwd=clone_path)
|
||||
logs = git.log_shas_and_timestamps(clone_path)
|
||||
context.watcher.change_progress(40)
|
||||
|
||||
if commits:
|
||||
commit_list = re.findall(r'commit (.+)\n', commits)
|
||||
if commit_list:
|
||||
if len(commit_list) > 1:
|
||||
srcfields = {'pkgver', 'pkgrel'}
|
||||
if not logs:
|
||||
context.watcher.show_message(title=self.i18n['arch.downgrade.error'],
|
||||
body=self.i18n['arch.downgrade.impossible'].format(
|
||||
context.name),
|
||||
type_=MessageType.ERROR)
|
||||
return False
|
||||
|
||||
commit_found = None
|
||||
for idx in range(1, len(commit_list)):
|
||||
commit = commit_list[idx]
|
||||
srcfields = {'pkgver', 'pkgrel', 'epoch'}
|
||||
|
||||
commit_found, commit_date = None, None
|
||||
for idx in range(1, len(logs)):
|
||||
commit, date = logs[idx][0], logs[idx][1]
|
||||
with open(srcinfo_path) as f:
|
||||
pkgsrc = aur.map_srcinfo(string=f.read(), pkgname=context.name, fields=srcfields)
|
||||
|
||||
@@ -640,9 +664,16 @@ class ArchManager(SoftwareManager):
|
||||
context.handler.watcher.print('Could not downgrade anymore. Aborting...')
|
||||
return False
|
||||
|
||||
if '{}-{}'.format(pkgsrc.get('pkgver'), pkgsrc.get('pkgrel')) == context.get_version():
|
||||
epoch, version, release = pkgsrc.get('epoch'), pkgsrc.get('pkgver'), pkgsrc.get('pkgrel')
|
||||
|
||||
if epoch:
|
||||
current_version = '{}:{}-{}'.format(epoch, version, release)
|
||||
else:
|
||||
current_version = '{}-{}'.format(version, release)
|
||||
|
||||
if current_version == context.get_version():
|
||||
# current version found
|
||||
commit_found = commit
|
||||
commit_found, commit_date = commit, date
|
||||
elif commit_found:
|
||||
context.watcher.change_substatus(self.i18n['arch.downgrade.version_found'])
|
||||
checkout_proc = new_subprocess(['git', 'checkout', commit_found], cwd=clone_path)
|
||||
@@ -658,18 +689,8 @@ class ArchManager(SoftwareManager):
|
||||
break
|
||||
|
||||
context.watcher.change_substatus(self.i18n['arch.downgrade.install_older'])
|
||||
context.last_modified = commit_date
|
||||
return self._build(context)
|
||||
else:
|
||||
context.watcher.show_message(title=self.i18n['arch.downgrade.error'],
|
||||
body=self.i18n['arch.downgrade.impossible'].format(context.name),
|
||||
type_=MessageType.ERROR)
|
||||
return False
|
||||
|
||||
context.watcher.show_message(title=self.i18n['error'],
|
||||
body=self.i18n['arch.downgrade.no_commits'],
|
||||
type_=MessageType.ERROR)
|
||||
return False
|
||||
|
||||
finally:
|
||||
if os.path.exists(context.build_dir) and context.config['aur_remove_build_dir']:
|
||||
context.handler.handle(SystemProcess(subproc=new_subprocess(['rm', '-rf', context.build_dir])))
|
||||
@@ -1071,8 +1092,24 @@ class ArchManager(SoftwareManager):
|
||||
|
||||
if aur_pkgs:
|
||||
watcher.change_status('{}...'.format(self.i18n['arch.upgrade.upgrade_aur_pkgs']))
|
||||
|
||||
self.logger.info("Retrieving the 'last_modified' field for each package to upgrade")
|
||||
pkgs_api_data = self.aur_client.get_info({p.name for p in aur_pkgs})
|
||||
|
||||
if not pkgs_api_data:
|
||||
self.logger.warning("Could not retrieve the 'last_modified' fields from the AUR API during the upgrade process")
|
||||
|
||||
for pkg in aur_pkgs:
|
||||
watcher.change_substatus("{} {} ({})...".format(self.i18n['manage_window.status.upgrading'], pkg.name, pkg.version))
|
||||
|
||||
if pkgs_api_data:
|
||||
apidata = [p for p in pkgs_api_data if p.get('Name') == pkg.name]
|
||||
|
||||
if not apidata:
|
||||
self.logger.warning("AUR API data from package '{}' could not be found".format(pkg.name))
|
||||
else:
|
||||
self.aur_mapper.fill_last_modified(pkg=pkg, api_data=apidata[0])
|
||||
|
||||
context = TransactionContext.gen_context_from(pkg=pkg, arch_config=arch_config,
|
||||
root_password=root_password, handler=handler)
|
||||
context.change_progress = False
|
||||
@@ -1329,11 +1366,15 @@ class ArchManager(SoftwareManager):
|
||||
|
||||
def _get_info_aur_pkg(self, pkg: ArchPackage) -> dict:
|
||||
if pkg.installed:
|
||||
t = Thread(target=self.mapper.fill_package_build, args=(pkg,), daemon=True)
|
||||
t = Thread(target=self.aur_mapper.fill_package_build, args=(pkg,), daemon=True)
|
||||
t.start()
|
||||
|
||||
info = pacman.get_info_dict(pkg.name)
|
||||
|
||||
if pkg.last_modified:
|
||||
info['last_modified'] = self._parse_timestamp(ts=pkg.last_modified,
|
||||
error_msg="Could not parse AUR package '{}' 'last_modified' field ({})".format(pkg.name, pkg.last_modified))
|
||||
|
||||
t.join()
|
||||
|
||||
if pkg.pkgbuild:
|
||||
@@ -1352,11 +1393,17 @@ class ArchManager(SoftwareManager):
|
||||
'05_votes': pkg.votes,
|
||||
'06_package_base': pkg.package_base,
|
||||
'07_maintainer': pkg.maintainer,
|
||||
'08_first_submitted': pkg.first_submitted,
|
||||
'09_last_modified': pkg.last_modified,
|
||||
'10_url': pkg.url_download
|
||||
}
|
||||
|
||||
if pkg.first_submitted:
|
||||
info['08_first_submitted'] = self._parse_timestamp(ts=pkg.first_submitted,
|
||||
error_msg="Could not parse AUR package '{}' 'first_submitted' field".format(pkg.name, pkg.first_submitted))
|
||||
|
||||
if pkg.last_modified:
|
||||
info['09_last_modified'] = self._parse_timestamp(ts=pkg.last_modified,
|
||||
error_msg="Could not parse AUR package '{}' 'last_modified' field ({})".format(pkg.name, pkg.last_modified))
|
||||
|
||||
srcinfo = self.aur_client.get_src_info(pkg.name)
|
||||
|
||||
if srcinfo:
|
||||
@@ -1383,6 +1430,14 @@ class ArchManager(SoftwareManager):
|
||||
|
||||
return info
|
||||
|
||||
def _parse_timestamp(self, ts: int, error_msg: str) -> datetime:
|
||||
if ts:
|
||||
try:
|
||||
return datetime.fromtimestamp(ts)
|
||||
except ValueError:
|
||||
if error_msg:
|
||||
self.logger.warning(error_msg)
|
||||
|
||||
def _get_info_repo_pkg(self, pkg: ArchPackage) -> dict:
|
||||
info = pacman.get_info_dict(pkg.name, remote=not pkg.installed)
|
||||
if pkg.installed:
|
||||
@@ -2205,6 +2260,7 @@ class ArchManager(SoftwareManager):
|
||||
cache_map = {context.name: ArchPackage(name=context.name,
|
||||
repository=context.repository,
|
||||
maintainer=pkg_maintainer,
|
||||
last_modified=context.last_modified,
|
||||
categories=self.categories.get(context.name))}
|
||||
if context.missing_deps:
|
||||
aur_deps = {dep[0] for dep in context.missing_deps if dep[1] == 'aur'}
|
||||
@@ -2344,7 +2400,7 @@ class ArchManager(SoftwareManager):
|
||||
watcher.change_substatus(self.i18n['arch.makepkg.optimizing'])
|
||||
ArchCompilationOptimizer(arch_config=arch_config, i18n=self.i18n, logger=self.context.logger).optimize()
|
||||
|
||||
def install(self, pkg: ArchPackage, root_password: str, disk_loader: DiskCacheLoader, watcher: ProcessWatcher, context: TransactionContext = None) -> TransactionResult:
|
||||
def install(self, pkg: ArchPackage, root_password: str, disk_loader: Optional[DiskCacheLoader], watcher: ProcessWatcher, context: TransactionContext = None) -> TransactionResult:
|
||||
self.aur_client.clean_caches()
|
||||
|
||||
if not self._check_action_allowed(pkg, watcher):
|
||||
@@ -2550,7 +2606,7 @@ class ArchManager(SoftwareManager):
|
||||
if not self._is_wget_available():
|
||||
warnings.append(self.i18n['arch.warning.disabled'].format(bold('wget')))
|
||||
|
||||
if not git.is_enabled():
|
||||
if not git.is_installed():
|
||||
warnings.append(self.i18n['arch.warning.git'].format(bold('git')))
|
||||
|
||||
return warnings
|
||||
@@ -2580,7 +2636,7 @@ class ArchManager(SoftwareManager):
|
||||
res = []
|
||||
for pkg in api_res:
|
||||
if pkg.get('Name') in suggestions:
|
||||
res.append(PackageSuggestion(self.mapper.map_api_data(pkg, {}, self.categories), suggestions[pkg['Name']]))
|
||||
res.append(PackageSuggestion(self.aur_mapper.map_api_data(pkg, {}, self.categories), suggestions[pkg['Name']]))
|
||||
|
||||
self.logger.info("Mapped {} suggestions".format(len(suggestions)))
|
||||
return res
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
from datetime import datetime
|
||||
from typing import List
|
||||
from typing import List, Tuple, Optional
|
||||
|
||||
from bauh.commons import system
|
||||
from bauh.commons.system import new_subprocess
|
||||
|
||||
|
||||
def is_enabled() -> bool:
|
||||
def is_installed() -> bool:
|
||||
try:
|
||||
new_subprocess(['git', '--version'])
|
||||
return True
|
||||
@@ -27,3 +28,18 @@ def list_commits(proj_dir:str) -> List[dict]:
|
||||
commit = {}
|
||||
|
||||
return commits
|
||||
|
||||
|
||||
def log_shas_and_timestamps(repo_path: str) -> Optional[List[Tuple[str, int]]]:
|
||||
code, output = system.execute(cmd='git log --format="%H %at"', shell=True, cwd=repo_path)
|
||||
|
||||
if code == 0:
|
||||
logs = []
|
||||
for line in output.strip().split('\n'):
|
||||
line_strip = line.strip()
|
||||
|
||||
if line_strip:
|
||||
line_split = line_strip.split(' ')
|
||||
logs.append((line_split[0].strip(), int(line_split[1].strip())))
|
||||
|
||||
return logs
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import logging
|
||||
import os
|
||||
import traceback
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from colorama import Fore
|
||||
from pkg_resources import parse_version
|
||||
@@ -13,41 +14,56 @@ from bauh.view.util.translation import I18n
|
||||
URL_PKG_DOWNLOAD = 'https://aur.archlinux.org/{}'
|
||||
|
||||
|
||||
class ArchDataMapper:
|
||||
class AURDataMapper:
|
||||
|
||||
def __init__(self, http_client: HttpClient, i18n: I18n):
|
||||
def __init__(self, http_client: HttpClient, i18n: I18n, logger: logging.Logger):
|
||||
self.http_client = http_client
|
||||
self.i18n = i18n
|
||||
self.logger = logger
|
||||
|
||||
def fill_api_data(self, pkg: ArchPackage, package: dict, fill_version: bool = True):
|
||||
def fill_last_modified(self, pkg: ArchPackage, api_data: dict):
|
||||
last_modified = api_data.get('LastModified')
|
||||
if last_modified is not None and isinstance(last_modified, int):
|
||||
pkg.last_modified = last_modified
|
||||
self.logger.info("'last_modified' field ({}) set to package '{}'".format(last_modified, pkg.name))
|
||||
else:
|
||||
self.logger.warning("Could not set the 'last_modified' field ({}) to package '{}'".format(last_modified, pkg.name))
|
||||
|
||||
version = package.get('Version')
|
||||
def fill_api_data(self, pkg: ArchPackage, api_data: dict, fill_version: bool = True):
|
||||
pkg.id = api_data.get('ID')
|
||||
|
||||
if not pkg.name:
|
||||
pkg.name = api_data.get('Name')
|
||||
|
||||
if not pkg.description:
|
||||
pkg.description = api_data.get('Description')
|
||||
|
||||
pkg.package_base = api_data.get('PackageBase')
|
||||
pkg.popularity = api_data.get('Popularity')
|
||||
pkg.votes = api_data.get('NumVotes')
|
||||
pkg.maintainer = api_data.get('Maintainer')
|
||||
pkg.url_download = URL_PKG_DOWNLOAD.format(api_data['URLPath']) if api_data.get('URLPath') else None
|
||||
|
||||
if api_data['FirstSubmitted'] and isinstance(api_data['FirstSubmitted'], int):
|
||||
pkg.first_submitted = api_data['FirstSubmitted']
|
||||
|
||||
if not pkg.installed:
|
||||
self.fill_last_modified(pkg=pkg, api_data=api_data)
|
||||
|
||||
version = api_data.get('Version')
|
||||
|
||||
if version:
|
||||
version = version.split(':')
|
||||
version = version[0] if len(version) == 1 else version[1]
|
||||
|
||||
pkg.id = package.get('ID')
|
||||
pkg.name = package.get('Name')
|
||||
|
||||
if fill_version:
|
||||
pkg.version = version
|
||||
|
||||
pkg.latest_version = version
|
||||
pkg.description = package.get('Description')
|
||||
|
||||
pkg.package_base = package.get('PackageBase')
|
||||
pkg.popularity = package.get('Popularity')
|
||||
pkg.votes = package.get('NumVotes')
|
||||
pkg.maintainer = package.get('Maintainer')
|
||||
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 = self.check_update(pkg.version, pkg.latest_version)
|
||||
|
||||
@staticmethod
|
||||
def check_update(version: str, latest_version: str) -> bool:
|
||||
if version and latest_version:
|
||||
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(':')
|
||||
|
||||
@@ -82,8 +98,8 @@ class ArchDataMapper:
|
||||
if res and res.status_code == 200 and res.text:
|
||||
pkg.pkgbuild = res.text
|
||||
|
||||
def map_api_data(self, apidata: dict, installed: dict, categories: dict) -> ArchPackage:
|
||||
data = installed.get(apidata.get('Name')) if installed else None
|
||||
def map_api_data(self, apidata: dict, pkgs_installed: Optional[dict], categories: dict) -> ArchPackage:
|
||||
data = pkgs_installed.get(apidata.get('Name')) if pkgs_installed else None
|
||||
app = ArchPackage(name=apidata.get('Name'), installed=bool(data), repository='aur', i18n=self.i18n)
|
||||
app.status = PackageStatus.LOADING_DATA
|
||||
|
||||
@@ -95,5 +111,26 @@ class ArchDataMapper:
|
||||
app.description = data.get('description')
|
||||
|
||||
self.fill_api_data(app, apidata, fill_version=not data)
|
||||
|
||||
return app
|
||||
|
||||
def check_update(self, pkg: ArchPackage, last_modified: Optional[int]) -> bool:
|
||||
valid_last_modified = last_modified is not None and isinstance(last_modified, int)
|
||||
|
||||
if not valid_last_modified:
|
||||
self.logger.warning("'last_modified' timestamp informed for package '{}' is invalid: {}".format(pkg.name, valid_last_modified))
|
||||
|
||||
pkg_last_modified_ts = pkg.last_modified if pkg.last_modified is not None else pkg.install_date
|
||||
|
||||
if pkg.last_modified is None:
|
||||
self.logger.warning("AUR package '{}' has no 'last_modified' field set.".format(pkg.name))
|
||||
|
||||
if pkg.install_date is None:
|
||||
self.logger.warning("AUR package '{}' has no 'install_date' field set".format(pkg.name))
|
||||
self.logger.warning("Update checking for AUR package '{}' will only consider version strings".format(pkg.name))
|
||||
else:
|
||||
self.logger.warning("AUR package {} 'install_date' field will be used for update checking".format(pkg.name))
|
||||
|
||||
if pkg_last_modified_ts is not None and valid_last_modified and pkg_last_modified_ts < last_modified:
|
||||
return True
|
||||
else:
|
||||
return self.check_version_update(pkg.version, pkg.latest_version)
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import datetime
|
||||
from typing import List, Set
|
||||
from typing import List, Set, Optional
|
||||
|
||||
from bauh.api.abstract.model import SoftwarePackage, CustomSoftwareAction
|
||||
from bauh.commons import resource
|
||||
from bauh.gems.arch import ROOT_DIR, ARCH_CACHE_PATH
|
||||
from bauh.view.util.translation import I18n
|
||||
|
||||
CACHED_ATTRS = {'command', 'icon_path', 'repository', 'maintainer', 'desktop_entry', 'categories'}
|
||||
CACHED_ATTRS = {'command', 'icon_path', 'repository', 'maintainer', 'desktop_entry', 'categories', 'last_modified'}
|
||||
|
||||
ACTIONS_AUR_ENABLE_PKGBUILD_EDITION = [CustomSoftwareAction(i18n_label_key='arch.action.enable_pkgbuild_edition',
|
||||
i18n_status_key='arch.action.enable_pkgbuild_edition.status',
|
||||
@@ -27,11 +26,11 @@ class ArchPackage(SoftwarePackage):
|
||||
|
||||
def __init__(self, name: str = None, version: str = None, latest_version: str = None, description: str = None,
|
||||
package_base: str = None, votes: int = None, popularity: float = None,
|
||||
first_submitted: datetime.datetime = None, last_modified: datetime.datetime = None,
|
||||
first_submitted: Optional[int] = None, last_modified: Optional[int] = None,
|
||||
maintainer: str = None, url_download: str = None, pkgbuild: str = None, repository: str = None,
|
||||
desktop_entry: str = None, installed: bool = False, srcinfo: dict = None, dependencies: Set[str] = None,
|
||||
categories: List[str] = None, i18n: I18n = None, update_ignored: bool = False, arch: str = None,
|
||||
pkgbuild_editable: bool = None):
|
||||
pkgbuild_editable: bool = None, install_date: Optional[int] = None):
|
||||
|
||||
super(ArchPackage, self).__init__(name=name, version=version, latest_version=latest_version, description=description,
|
||||
installed=installed, categories=categories)
|
||||
@@ -55,6 +54,7 @@ class ArchPackage(SoftwarePackage):
|
||||
self.update_ignored = update_ignored
|
||||
self.view_name = name # name displayed on the view
|
||||
self.pkgbuild_editable = pkgbuild_editable # if the PKGBUILD can be edited by the user (only for AUR)
|
||||
self.install_date = install_date
|
||||
|
||||
@staticmethod
|
||||
def disk_cache_path(pkgname: str):
|
||||
|
||||
@@ -15,7 +15,7 @@ RE_DEPS = re.compile(r'[\w\-_]+:[\s\w_\-\.]+\s+\[\w+\]')
|
||||
RE_OPTDEPS = re.compile(r'[\w\._\-]+\s*:')
|
||||
RE_DEP_NOTFOUND = re.compile(r'error:.+\'(.+)\'')
|
||||
RE_DEP_OPERATORS = re.compile(r'[<>=]')
|
||||
RE_INSTALLED_FIELDS = re.compile(r'(Name|Description|Version|Validated By)\s*:\s*(.+)')
|
||||
RE_INSTALLED_FIELDS = re.compile(r'(Name|Description|Version|Install Date|Validated By)\s*:\s*(.+)')
|
||||
RE_INSTALLED_SIZE = re.compile(r'Installed Size\s*:\s*([0-9,\.]+)\s(\w+)\n?', re.IGNORECASE)
|
||||
RE_DOWNLOAD_SIZE = re.compile(r'Download Size\s*:\s*([0-9,\.]+)\s(\w+)\n?', re.IGNORECASE)
|
||||
RE_UPDATE_REQUIRED_FIELDS = re.compile(r'(\bProvides\b|\bInstalled Size\b|\bConflicts With\b)\s*:\s(.+)\n')
|
||||
@@ -114,9 +114,11 @@ def map_installed(names: Iterable[str] = None) -> dict: # returns a dict with w
|
||||
if field_tuple[0].startswith('N'):
|
||||
current_pkg['name'] = field_tuple[1].strip()
|
||||
elif field_tuple[0].startswith('Ve'):
|
||||
current_pkg['version'] = field_tuple[1].split(':')[-1].strip()
|
||||
current_pkg['version'] = field_tuple[1].strip()
|
||||
elif field_tuple[0].startswith('D'):
|
||||
current_pkg['description'] = field_tuple[1].strip()
|
||||
elif field_tuple[0].startswith('I'):
|
||||
current_pkg['install_date'] = field_tuple[1].strip()
|
||||
elif field_tuple[0].startswith('Va'):
|
||||
if field_tuple[1].strip().lower() == 'none':
|
||||
pkgs['not_signed'][current_pkg['name']] = current_pkg
|
||||
@@ -449,8 +451,7 @@ def search(words: str) -> Dict[str, dict]:
|
||||
data_split = repo_split[1].split(' ')
|
||||
current['name'] = data_split[0]
|
||||
|
||||
version = data_split[1].split(':')
|
||||
current['version'] = version[0] if len(version) == 1 else version[1]
|
||||
current['version'] = data_split[1]
|
||||
return found
|
||||
|
||||
|
||||
|
||||
@@ -144,6 +144,7 @@ arch.info.install script=script d'instal·lació
|
||||
arch.info.install script.no=no
|
||||
arch.info.installed files=arxius instal·lats
|
||||
arch.info.installed size=mida instal·lat
|
||||
arch.info.last_modified=última modificació
|
||||
arch.info.license=llicència
|
||||
arch.info.licenses=llicències
|
||||
arch.info.licenses.custom=costum
|
||||
|
||||
@@ -144,6 +144,7 @@ arch.info.install script=Installationsskript
|
||||
arch.info.install script.no=Nein
|
||||
arch.info.installed files=installierten Dateien
|
||||
arch.info.installed size=installierte Größe
|
||||
arch.info.last_modified=zuletzt bearbeitet
|
||||
arch.info.license=Lizenz
|
||||
arch.info.licenses=Lizenzen
|
||||
arch.info.licenses.custom=Benutzerdefiniert
|
||||
|
||||
@@ -144,6 +144,7 @@ arch.info.install script=install script
|
||||
arch.info.install script.no=no
|
||||
arch.info.installed files=installed files
|
||||
arch.info.installed size=installed size
|
||||
arch.info.last_modified=last modified
|
||||
arch.info.license=license
|
||||
arch.info.licenses=licenses
|
||||
arch.info.licenses.custom=custom
|
||||
|
||||
@@ -144,6 +144,7 @@ arch.info.install script=script de instalación
|
||||
arch.info.install script.no=ninguno
|
||||
arch.info.installed files=archivos instalados
|
||||
arch.info.installed size=tamaño da instalación
|
||||
arch.info.last_modified=última modificación
|
||||
arch.info.license=licencia
|
||||
arch.info.licenses=licencias
|
||||
arch.info.licenses.custom=personalizada
|
||||
|
||||
@@ -144,6 +144,7 @@ arch.info.install script=script d'installation
|
||||
arch.info.install script.no=non
|
||||
arch.info.installed files=fichiers installés
|
||||
arch.info.installed size=taille installée
|
||||
arch.info.last_modified=dernière modification
|
||||
arch.info.license=licence
|
||||
arch.info.licenses=licences
|
||||
arch.info.licenses.custom=personnalisé
|
||||
|
||||
@@ -144,6 +144,7 @@ arch.info.install script=script di installazione
|
||||
arch.info.install script.no=nessuno
|
||||
arch.info.installed files=file installati
|
||||
arch.info.installed size=taglia installata
|
||||
arch.info.last_modified=Ultima modifica
|
||||
arch.info.license=licenza
|
||||
arch.info.licenses=licenze
|
||||
arch.info.licenses.custom=costume
|
||||
|
||||
@@ -143,6 +143,7 @@ arch.info.install script=script de instalação
|
||||
arch.info.install script.no=nenhum
|
||||
arch.info.installed files=arquivos instalados
|
||||
arch.info.installed size=tamanho da instalação
|
||||
arch.info.last_modified=última modificação
|
||||
arch.info.license=licença
|
||||
arch.info.licenses=licenças
|
||||
arch.info.licenses.custom=personalizada
|
||||
|
||||
@@ -144,6 +144,7 @@ arch.info.install script=Скрипт установки
|
||||
arch.info.install script.no=Нет
|
||||
arch.info.installed files=установленные файлы
|
||||
arch.info.installed size=Размер установки
|
||||
arch.info.last_modified=Последнее изменение
|
||||
arch.info.license=Лицензия
|
||||
arch.info.licenses=Лицензии
|
||||
arch.info.licenses.custom=таможенная
|
||||
|
||||
@@ -144,6 +144,7 @@ arch.info.install script=kurulum betiği
|
||||
arch.info.install script.no=hayır
|
||||
arch.info.installed files=yüklü dosyalar
|
||||
arch.info.installed size=kurulum boyutu
|
||||
arch.info.last_modified=son değişiklik
|
||||
arch.info.license=lisans
|
||||
arch.info.licenses=lisanslar
|
||||
arch.info.licenses.custom=özel
|
||||
|
||||
@@ -390,6 +390,7 @@ style=estil
|
||||
success=success
|
||||
summary=resum
|
||||
task.download_categories=Download de categories [ {} ]
|
||||
task.waiting_task=Waiting for {}
|
||||
type=tipus
|
||||
uninstall=desinstal·la
|
||||
uninstalled=desinstal·lada
|
||||
|
||||
@@ -390,6 +390,7 @@ style=Stil
|
||||
success=success
|
||||
summary=Zusammenfassung
|
||||
task.download_categories=Downloading categories [ {} ]
|
||||
task.waiting_task=Waiting for {}
|
||||
type=Typ
|
||||
uninstall=Deinstallation
|
||||
uninstalled=deinstalliert
|
||||
|
||||
@@ -391,6 +391,7 @@ style=style
|
||||
success=success
|
||||
summary=summary
|
||||
task.download_categories=Downloading categories [ {} ]
|
||||
task.waiting_task=Waiting for {}
|
||||
type=type
|
||||
uninstall=uninstall
|
||||
uninstalled=uninstalled
|
||||
|
||||
@@ -393,6 +393,7 @@ style=estilo
|
||||
success=éxito
|
||||
summary=resumen
|
||||
task.download_categories=Descargando categorías [ {} ]
|
||||
task.waiting_task=Esperando por {}
|
||||
type=tipo
|
||||
uninstall=desinstalar
|
||||
uninstalled=desinstalada
|
||||
|
||||
@@ -387,6 +387,7 @@ style=style
|
||||
success=succès
|
||||
summary=résumé
|
||||
task.download_categories=Téléchargement des catégories [ {} ]
|
||||
task.waiting_task=Waiting for {}
|
||||
type=type
|
||||
uninstall=désinstaller
|
||||
uninstalled=désinstallé
|
||||
|
||||
@@ -393,6 +393,7 @@ style=stile
|
||||
success=success
|
||||
summary=riepilogo
|
||||
task.download_categories=Download delle categorie [ {} ]
|
||||
task.waiting_task=Waiting for {}
|
||||
type=tipe
|
||||
uninstall=Disinstalla
|
||||
uninstalled=disinstallato
|
||||
|
||||
@@ -391,6 +391,7 @@ style=estilo
|
||||
success=sucesso
|
||||
summary=resumo
|
||||
task.download_categories=Baixando categorias [ {} ]
|
||||
task.waiting_task=Aguardando {}
|
||||
type=tipo
|
||||
uninstall=desinstalar
|
||||
uninstalled=desinstalado
|
||||
|
||||
@@ -390,6 +390,7 @@ style=Стиль
|
||||
success=success
|
||||
summary=Суммарно
|
||||
task.download_categories=Downloading categories [ {} ]
|
||||
task.waiting_task=Waiting for {}
|
||||
type=Тип
|
||||
uninstall=Деинсталляция
|
||||
uninstalled=Деинсталлировано
|
||||
|
||||
@@ -390,6 +390,7 @@ style=Görünüm biçimi
|
||||
success=başarılı
|
||||
summary=özet
|
||||
task.download_categories=Kategoriler indiriliyor [ {} ]
|
||||
task.waiting_task=Waiting for {}
|
||||
type=tür
|
||||
uninstall=kaldır
|
||||
uninstalled=kaldırıldı
|
||||
|
||||
@@ -23,13 +23,17 @@ class AsyncDiskCacheLoader(Thread, DiskCacheLoader):
|
||||
self.logger = logger
|
||||
self.processed = 0
|
||||
|
||||
def fill(self, pkg: SoftwarePackage):
|
||||
def fill(self, pkg: SoftwarePackage, sync: bool = False):
|
||||
"""
|
||||
Adds a package which data must be read from the disk to a queue.
|
||||
Adds a package which data must be read from the disk to a queue (if not sync)
|
||||
:param pkg:
|
||||
:param sync:
|
||||
:return:
|
||||
"""
|
||||
if pkg and pkg.supports_disk_cache():
|
||||
if sync:
|
||||
self._fill_cached_data(pkg)
|
||||
else:
|
||||
self.pkgs.append(pkg)
|
||||
|
||||
def stop_working(self):
|
||||
|
||||
@@ -2,3 +2,4 @@ pyqt5>=5.12
|
||||
requests>=2.18
|
||||
colorama>=0.3.8
|
||||
pyyaml>=3.13
|
||||
python-dateutil>=2.7
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
from unittest import TestCase
|
||||
|
||||
from bauh.gems.arch.mapper import ArchDataMapper
|
||||
|
||||
|
||||
class ArchDataMapperTest(TestCase):
|
||||
|
||||
def test_check_update(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'))
|
||||
self.assertTrue(ArchDataMapper.check_update('77.0.3865.90-1', '77.0.3865.120-1'))
|
||||
self.assertTrue(ArchDataMapper.check_update('77.0.3865.90-1', '77.0.3865.90-2'))
|
||||
self.assertFalse(ArchDataMapper.check_update('77.0.3865.900-1', '77.0.3865.120-1'))
|
||||
self.assertTrue(ArchDataMapper.check_update('77.0.3865.120-1', '77.0.3865.900-1'))
|
||||
self.assertFalse(ArchDataMapper.check_update('77.0.3865.120-1', '77.0.3865.90-1'))
|
||||
self.assertTrue(ArchDataMapper.check_update('77.0.3865.a-1', '77.0.3865.b-1'))
|
||||
self.assertFalse(ArchDataMapper.check_update('77.0.b.0-1', '77.0.a.1-1'))
|
||||
self.assertFalse(ArchDataMapper.check_update('r25.e22697c-1', 'r8.19fe011-1'))
|
||||
self.assertTrue(ArchDataMapper.check_update('0.9.7.RC-9', '0.9.7.RC-10'))
|
||||
self.assertFalse(ArchDataMapper.check_update('1.1.0.r11.caacf30-1', 'r65.4c7144a-1'))
|
||||
self.assertFalse(ArchDataMapper.check_update('1.2.16.r688.8b2c199-1', 'r2105.e91f0e9-3'))
|
||||
|
||||
def test_check_update__versions_with_epics(self):
|
||||
self.assertTrue(ArchDataMapper.check_update('1.2-1', '1:1.1-1'))
|
||||
self.assertFalse(ArchDataMapper.check_update('1:1.1-1', '1.2-1'))
|
||||
|
||||
self.assertTrue(ArchDataMapper.check_update('1:1.2-1', '2:0.1-1'))
|
||||
self.assertFalse(ArchDataMapper.check_update('2:0.1-1', '1:1.2-1'))
|
||||
|
||||
self.assertTrue(ArchDataMapper.check_update('10:1.1-1', '10:1.2-1'))
|
||||
self.assertFalse(ArchDataMapper.check_update('10:1.2-1', '10:1.2-1'))
|
||||
|
||||
self.assertTrue(ArchDataMapper.check_update('9:1.2-1', '10:0.1-1'))
|
||||
|
||||
self.assertTrue(ArchDataMapper.check_update('9:1.1.1.1-2', '10:0.0'))
|
||||
self.assertFalse(ArchDataMapper.check_update('10:0.0', '9:1.1.1.1-2'))
|
||||
178
tests/gems/arch/test_aur_data_mapper.py
Normal file
178
tests/gems/arch/test_aur_data_mapper.py
Normal file
@@ -0,0 +1,178 @@
|
||||
from unittest import TestCase
|
||||
from unittest.mock import Mock
|
||||
|
||||
from bauh.gems.arch.mapper import AURDataMapper
|
||||
from bauh.gems.arch.model import ArchPackage
|
||||
|
||||
|
||||
class ArchDataMapperTest(TestCase):
|
||||
|
||||
def test_check_version_update(self):
|
||||
self.assertTrue(AURDataMapper.check_version_update('1.0.0-1', '1.0.0-2'))
|
||||
self.assertFalse(AURDataMapper.check_version_update('1.0.0-2', '1.0.0-1'))
|
||||
self.assertTrue(AURDataMapper.check_version_update('1.0.0-5', '1.0.1-1'))
|
||||
self.assertFalse(AURDataMapper.check_version_update('1.0.1-1', '1.0.0-1'))
|
||||
self.assertTrue(AURDataMapper.check_version_update('1.0.5-5', '1.1.0-2'))
|
||||
self.assertFalse(AURDataMapper.check_version_update('1.1.0-2', '1.0.5-5'))
|
||||
self.assertTrue(AURDataMapper.check_version_update('1.5.0-2', '1.5.1-1'))
|
||||
self.assertFalse(AURDataMapper.check_version_update('1.5.1-1', '1.5.0-2'))
|
||||
self.assertTrue(AURDataMapper.check_version_update('1.5.1-1', '1.5.1-2'))
|
||||
self.assertTrue(AURDataMapper.check_version_update('1.5.1-1', '2.0.0-1'))
|
||||
self.assertFalse(AURDataMapper.check_version_update('2.0.0-1', '1.5.1-1'))
|
||||
self.assertTrue(AURDataMapper.check_version_update('77.0.3865.90-1', '77.0.3865.120-1'))
|
||||
self.assertTrue(AURDataMapper.check_version_update('77.0.3865.90-1', '77.0.3865.90-2'))
|
||||
self.assertFalse(AURDataMapper.check_version_update('77.0.3865.900-1', '77.0.3865.120-1'))
|
||||
self.assertTrue(AURDataMapper.check_version_update('77.0.3865.120-1', '77.0.3865.900-1'))
|
||||
self.assertFalse(AURDataMapper.check_version_update('77.0.3865.120-1', '77.0.3865.90-1'))
|
||||
self.assertTrue(AURDataMapper.check_version_update('77.0.3865.a-1', '77.0.3865.b-1'))
|
||||
self.assertFalse(AURDataMapper.check_version_update('77.0.b.0-1', '77.0.a.1-1'))
|
||||
self.assertFalse(AURDataMapper.check_version_update('r25.e22697c-1', 'r8.19fe011-1'))
|
||||
self.assertTrue(AURDataMapper.check_version_update('0.9.7.RC-9', '0.9.7.RC-10'))
|
||||
self.assertFalse(AURDataMapper.check_version_update('1.1.0.r11.caacf30-1', 'r65.4c7144a-1'))
|
||||
self.assertFalse(AURDataMapper.check_version_update('1.2.16.r688.8b2c199-1', 'r2105.e91f0e9-3'))
|
||||
|
||||
def test_check_version_update__versions_with_epics(self):
|
||||
self.assertTrue(AURDataMapper.check_version_update('1.2-1', '1:1.1-1'))
|
||||
self.assertFalse(AURDataMapper.check_version_update('1:1.1-1', '1.2-1'))
|
||||
|
||||
self.assertTrue(AURDataMapper.check_version_update('1:1.2-1', '2:0.1-1'))
|
||||
self.assertFalse(AURDataMapper.check_version_update('2:0.1-1', '1:1.2-1'))
|
||||
|
||||
self.assertTrue(AURDataMapper.check_version_update('10:1.1-1', '10:1.2-1'))
|
||||
self.assertFalse(AURDataMapper.check_version_update('10:1.2-1', '10:1.2-1'))
|
||||
|
||||
self.assertTrue(AURDataMapper.check_version_update('9:1.2-1', '10:0.1-1'))
|
||||
|
||||
self.assertTrue(AURDataMapper.check_version_update('9:1.1.1.1-2', '10:0.0'))
|
||||
self.assertFalse(AURDataMapper.check_version_update('10:0.0', '9:1.1.1.1-2'))
|
||||
|
||||
def test_check_update__pkg_no_last_modified_and_same_versions(self):
|
||||
mapper = AURDataMapper(i18n=Mock(), logger=Mock(), http_client=Mock())
|
||||
pkg = ArchPackage(name='test')
|
||||
pkg.last_modified = None
|
||||
pkg.version = '1.0.0'
|
||||
pkg.latest_version = pkg.version
|
||||
|
||||
self.assertFalse(mapper.check_update(pkg=pkg, last_modified=1608143812))
|
||||
|
||||
def test_check_update__pkg_no_last_modified_and_latest_version_higher_than_version(self):
|
||||
mapper = AURDataMapper(i18n=Mock(), logger=Mock(), http_client=Mock())
|
||||
pkg = ArchPackage(name='test')
|
||||
pkg.last_modified = None
|
||||
pkg.version = '1.0.0'
|
||||
pkg.latest_version = '1.1.0'
|
||||
|
||||
self.assertTrue(mapper.check_update(pkg=pkg, last_modified=1608143812))
|
||||
|
||||
def test_check_update__pkg_no_last_modified_and_no_install_date_and_version_higher_than_latest_version(self):
|
||||
mapper = AURDataMapper(i18n=Mock(), logger=Mock(), http_client=Mock())
|
||||
pkg = ArchPackage(name='test')
|
||||
pkg.last_modified = None
|
||||
pkg.install_date = None
|
||||
pkg.version = '1.1.0'
|
||||
pkg.latest_version = '1.0.0'
|
||||
|
||||
self.assertFalse(mapper.check_update(pkg=pkg, last_modified=1608143812))
|
||||
|
||||
def test_check_update__none_last_modified_and_latest_version_higher_than_version(self):
|
||||
mapper = AURDataMapper(i18n=Mock(), logger=Mock(), http_client=Mock())
|
||||
pkg = ArchPackage(name='test')
|
||||
pkg.last_modified = 1608143812
|
||||
pkg.version = '1.0.0'
|
||||
pkg.latest_version = '1.1.0'
|
||||
|
||||
self.assertTrue(mapper.check_update(pkg=pkg, last_modified=None))
|
||||
|
||||
def test_check_update__none_last_modified_and_version_equal_latest_version(self):
|
||||
mapper = AURDataMapper(i18n=Mock(), logger=Mock(), http_client=Mock())
|
||||
pkg = ArchPackage(name='test')
|
||||
pkg.last_modified = 1608143812
|
||||
pkg.version = '1.0.0'
|
||||
pkg.latest_version = pkg.version
|
||||
|
||||
self.assertFalse(mapper.check_update(pkg=pkg, last_modified=None))
|
||||
|
||||
def test_check_update__string_last_modified_and_latest_version_higher_than_version(self):
|
||||
mapper = AURDataMapper(i18n=Mock(), logger=Mock(), http_client=Mock())
|
||||
pkg = ArchPackage(name='test')
|
||||
pkg.last_modified = 1608143812
|
||||
pkg.version = '1.0.0'
|
||||
pkg.latest_version = '1.1.0'
|
||||
|
||||
self.assertTrue(mapper.check_update(pkg=pkg, last_modified='abc'))
|
||||
|
||||
def test_check_update__pkg_last_modified_equal_last_modified_and_version_equal_latest_version(self):
|
||||
mapper = AURDataMapper(i18n=Mock(), logger=Mock(), http_client=Mock())
|
||||
pkg = ArchPackage(name='test')
|
||||
pkg.last_modified = 1608143812
|
||||
pkg.version = '1.0.0'
|
||||
pkg.latest_version = pkg.version
|
||||
|
||||
self.assertFalse(mapper.check_update(pkg=pkg, last_modified=pkg.last_modified))
|
||||
|
||||
def test_check_update__pkg_last_modified_higher_than_last_modified_and_latest_version_higher_than_version(self):
|
||||
mapper = AURDataMapper(i18n=Mock(), logger=Mock(), http_client=Mock())
|
||||
pkg = ArchPackage(name='test')
|
||||
pkg.last_modified = 1608143812
|
||||
pkg.version = '1.0.0'
|
||||
pkg.latest_version = '1.1.0'
|
||||
|
||||
self.assertTrue(mapper.check_update(pkg=pkg, last_modified=pkg.last_modified - 100))
|
||||
|
||||
def test_check_update__pkg_last_modified_less_than_last_modified_and_version_higher_than_latest_version(self):
|
||||
mapper = AURDataMapper(i18n=Mock(), logger=Mock(), http_client=Mock())
|
||||
pkg = ArchPackage(name='test')
|
||||
pkg.last_modified = 1608143812
|
||||
pkg.version = '2.0.0'
|
||||
pkg.latest_version = '1.0.0'
|
||||
|
||||
# in this case, last modified is more relevant than the string version
|
||||
self.assertTrue(mapper.check_update(pkg=pkg, last_modified=pkg.last_modified + 100))
|
||||
|
||||
def test_check_update__pkg_no_last_modified_and_install_date_less_than_last_modified_and_version_higher_than_latest(self):
|
||||
mapper = AURDataMapper(i18n=Mock(), logger=Mock(), http_client=Mock())
|
||||
pkg = ArchPackage(name='test')
|
||||
pkg.last_modified = None
|
||||
pkg.install_date = 1608143812
|
||||
pkg.version = '3.0.0'
|
||||
pkg.latest_version = '2.0.0'
|
||||
|
||||
# in this case, install_date will be considered instead of package's last_modified.
|
||||
# even that 'version' is higher than 'latest_version', 'last_modified' is greater than 'install_date'
|
||||
self.assertTrue(mapper.check_update(pkg=pkg, last_modified=pkg.install_date + 100))
|
||||
|
||||
def test_check_update__pkg_no_last_modified_and_install_date_higher_than_last_modified_and_version_equal_latest(self):
|
||||
mapper = AURDataMapper(i18n=Mock(), logger=Mock(), http_client=Mock())
|
||||
pkg = ArchPackage(name='test')
|
||||
pkg.last_modified = None
|
||||
pkg.install_date = 1608143812
|
||||
pkg.version = '2.0.0'
|
||||
pkg.latest_version = pkg.version
|
||||
|
||||
# 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.assertFalse(mapper.check_update(pkg=pkg, last_modified=pkg.install_date - 100))
|
||||
|
||||
def test_check_update__pkg_no_last_modified_and_install_date_higher_than_last_modified_and_latest_higher(self):
|
||||
mapper = AURDataMapper(i18n=Mock(), logger=Mock(), http_client=Mock())
|
||||
pkg = ArchPackage(name='test')
|
||||
pkg.last_modified = None
|
||||
pkg.install_date = 1608143812
|
||||
pkg.version = '1.0.0'
|
||||
pkg.latest_version = '1.1.0'
|
||||
|
||||
# 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=pkg.install_date - 100))
|
||||
|
||||
def test_check_update__pkg_no_last_modified_and_install_date_and_no_last_modified_and_latest_higher(self):
|
||||
mapper = AURDataMapper(i18n=Mock(), logger=Mock(), http_client=Mock())
|
||||
pkg = ArchPackage(name='test')
|
||||
pkg.last_modified = None
|
||||
pkg.install_date = 1608143812
|
||||
pkg.version = '1.0.0'
|
||||
pkg.latest_version = '1.1.0'
|
||||
|
||||
# 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))
|
||||
Reference in New Issue
Block a user