mirror of
https://github.com/spalencsar/bearhub.git
synced 2026-07-07 02:24:16 +02:00
AUR bearhub: fix stale source cache collision (pkgrel=10)
Use tag-specific tarball name bearhub-0.10.7-bearhub.6.tar.gz so makepkg and AUR helpers do not reuse an outdated bearhub-0.10.7.tar.gz from cache. Ignore makepkg artifacts under packaging/aur/.
This commit is contained in:
@@ -1,89 +0,0 @@
|
||||
import datetime
|
||||
from threading import Lock
|
||||
from typing import Optional
|
||||
|
||||
from bauh.api.abstract.cache import MemoryCache, MemoryCacheFactory
|
||||
|
||||
|
||||
class DefaultMemoryCache(MemoryCache):
|
||||
"""
|
||||
A synchronized cache implementation
|
||||
"""
|
||||
|
||||
def __init__(self, expiration_time: int):
|
||||
super(DefaultMemoryCache, self).__init__()
|
||||
self.expiration_time = expiration_time
|
||||
self._cache = {}
|
||||
self.lock = Lock()
|
||||
|
||||
def is_enabled(self):
|
||||
return self.expiration_time < 0 or self.expiration_time > 0
|
||||
|
||||
def add(self, key: str, val: object):
|
||||
if key and self.is_enabled():
|
||||
self.lock.acquire()
|
||||
self._add(key, val)
|
||||
self.lock.release()
|
||||
|
||||
def _add(self, key: str, val: object):
|
||||
if key:
|
||||
self._cache[key] = {'val': val, 'expires_at': datetime.datetime.now(UTC) + datetime.timedelta(seconds=self.expiration_time) if self.expiration_time > 0 else None}
|
||||
|
||||
def add_non_existing(self, key: str, val: object):
|
||||
if key and self. is_enabled():
|
||||
self.lock.acquire()
|
||||
cur_val = self.get(key, lock=False)
|
||||
|
||||
if cur_val is None:
|
||||
self._add(key, val)
|
||||
|
||||
self.lock.release()
|
||||
|
||||
def get(self, key: str, lock: bool = True):
|
||||
if key and self.is_enabled():
|
||||
val = self._cache.get(key)
|
||||
|
||||
if val:
|
||||
expiration = val.get('expires_at')
|
||||
|
||||
if expiration and expiration <= datetime.datetime.now(UTC):
|
||||
if lock:
|
||||
self.lock.acquire()
|
||||
|
||||
del self._cache[key]
|
||||
|
||||
if lock:
|
||||
self.lock.release()
|
||||
|
||||
return None
|
||||
|
||||
return val['val']
|
||||
|
||||
def delete(self, key):
|
||||
if key and self.is_enabled():
|
||||
if key in self._cache:
|
||||
self.lock.acquire()
|
||||
del self._cache[key]
|
||||
self.lock.release()
|
||||
|
||||
def keys(self):
|
||||
return set(self._cache.keys()) if self.is_enabled() else set()
|
||||
|
||||
def clean_expired(self):
|
||||
if self.is_enabled():
|
||||
for key in self.keys():
|
||||
self.get(key)
|
||||
|
||||
|
||||
class DefaultMemoryCacheFactory(MemoryCacheFactory):
|
||||
|
||||
def __init__(self, expiration_time: int):
|
||||
"""
|
||||
:param expiration_time: default expiration time for all instantiated caches
|
||||
"""
|
||||
super(DefaultMemoryCacheFactory, self).__init__()
|
||||
self.expiration_time = expiration_time
|
||||
|
||||
def new(self, expiration: Optional[int] = None) -> MemoryCache:
|
||||
return DefaultMemoryCache(expiration if expiration is not None else self.expiration_time)
|
||||
UTC = datetime.timezone.utc
|
||||
@@ -1,115 +0,0 @@
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import time
|
||||
from threading import Thread, Lock
|
||||
from typing import Type, Dict, Any, Optional
|
||||
|
||||
import yaml
|
||||
|
||||
from bauh.api.abstract.cache import MemoryCache
|
||||
from bauh.api.abstract.disk import DiskCacheLoader, DiskCacheLoaderFactory
|
||||
from bauh.api.abstract.model import SoftwarePackage
|
||||
|
||||
|
||||
class AsyncDiskCacheLoader(Thread, DiskCacheLoader):
|
||||
|
||||
def __init__(self, cache_map: Dict[Type[SoftwarePackage], MemoryCache], logger: logging.Logger):
|
||||
super(AsyncDiskCacheLoader, self).__init__(daemon=True)
|
||||
self.pkgs = []
|
||||
self._work = True
|
||||
self.lock = Lock()
|
||||
self.cache_map = cache_map
|
||||
self.logger = logger
|
||||
self.processed = 0
|
||||
self._working = False
|
||||
|
||||
def fill(self, pkg: SoftwarePackage, sync: bool = False):
|
||||
"""
|
||||
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 or not self._working:
|
||||
self._fill_cached_data(pkg)
|
||||
else:
|
||||
self.pkgs.append(pkg)
|
||||
|
||||
def read(self, pkg: SoftwarePackage) -> Optional[Dict[str, Any]]:
|
||||
if pkg and pkg.supports_disk_cache():
|
||||
data_path = pkg.get_disk_data_path()
|
||||
|
||||
if data_path and os.path.isfile(data_path):
|
||||
ext = data_path.split('.')[-1]
|
||||
|
||||
try:
|
||||
with open(data_path) as f:
|
||||
file_content = f.read()
|
||||
except FileNotFoundError:
|
||||
return
|
||||
|
||||
if file_content:
|
||||
if ext == 'json':
|
||||
cached_data = json.loads(file_content)
|
||||
elif ext in {'yml', 'yaml'}:
|
||||
cached_data = yaml.load(file_content)
|
||||
else:
|
||||
raise Exception(f'The cached data file {data_path} has an unsupported format')
|
||||
|
||||
if cached_data:
|
||||
return cached_data
|
||||
|
||||
else:
|
||||
self.logger.warning(f"No cached content in file {data_path}")
|
||||
|
||||
def stop_working(self):
|
||||
self._work = False
|
||||
|
||||
def run(self):
|
||||
self._working = True
|
||||
last = 0
|
||||
|
||||
while True:
|
||||
time.sleep(0.00001)
|
||||
if len(self.pkgs) > self.processed:
|
||||
pkg = self.pkgs[last]
|
||||
|
||||
self._fill_cached_data(pkg)
|
||||
self.processed += 1
|
||||
last += 1
|
||||
elif not self._work:
|
||||
break
|
||||
|
||||
self._working = False
|
||||
|
||||
def _fill_cached_data(self, pkg: SoftwarePackage) -> bool:
|
||||
cached_data = self.read(pkg)
|
||||
|
||||
if cached_data:
|
||||
pkg.fill_cached_data(cached_data)
|
||||
cache = self.cache_map.get(pkg.__class__)
|
||||
|
||||
if cache:
|
||||
cache.add_non_existing(str(pkg.id), cached_data)
|
||||
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
class DefaultDiskCacheLoaderFactory(DiskCacheLoaderFactory):
|
||||
|
||||
def __init__(self, logger: logging.Logger):
|
||||
super(DefaultDiskCacheLoaderFactory, self).__init__()
|
||||
self.logger = logger
|
||||
self.cache_map = {}
|
||||
|
||||
def map(self, pkg_type: Type[SoftwarePackage], cache: MemoryCache):
|
||||
if pkg_type:
|
||||
if pkg_type not in self.cache_map:
|
||||
self.cache_map[pkg_type] = cache
|
||||
|
||||
def new(self) -> AsyncDiskCacheLoader:
|
||||
return AsyncDiskCacheLoader(cache_map=self.cache_map, logger=self.logger)
|
||||
@@ -1,22 +0,0 @@
|
||||
import logging
|
||||
from logging import INFO
|
||||
|
||||
FORMAT = '%(asctime)s %(levelname)s [%(module_path)s:%(lineno)s - %(funcName)s()] - %(message)s'
|
||||
|
||||
|
||||
class FilePathFilter(logging.Filter):
|
||||
|
||||
def filter(self, record):
|
||||
record.module_path = record.pathname.split('site-packages/')[1] if 'site-packages' in record.pathname else str(record.pathname)
|
||||
return True
|
||||
|
||||
|
||||
def new_logger(name: str, enabled: bool) -> logging.Logger:
|
||||
instance = logging.Logger(name, level=INFO)
|
||||
instance.addFilter(FilePathFilter())
|
||||
stream_handler = logging.StreamHandler()
|
||||
stream_handler.setFormatter(logging.Formatter(FORMAT))
|
||||
instance.addHandler(stream_handler)
|
||||
instance.disabled = not enabled
|
||||
|
||||
return instance
|
||||
@@ -1,5 +0,0 @@
|
||||
from bauh import ROOT_DIR
|
||||
|
||||
|
||||
def get_path(resource_path):
|
||||
return ROOT_DIR + '/view/resources/' + resource_path
|
||||
@@ -1,89 +0,0 @@
|
||||
import glob
|
||||
import locale
|
||||
import os
|
||||
from typing import Tuple, Set
|
||||
|
||||
from bauh.view.util import resource
|
||||
|
||||
|
||||
class I18n(dict):
|
||||
|
||||
def __init__(self, current_key: str, current_locale: dict, default_key: str, default_locale: dict):
|
||||
super(I18n, self).__init__()
|
||||
self.current_key = current_key
|
||||
self.current = current_locale
|
||||
self.default_key = default_key
|
||||
self.default = default_locale
|
||||
|
||||
def __getitem__(self, item):
|
||||
try:
|
||||
return self.current.__getitem__(item)
|
||||
except KeyError:
|
||||
if self.default:
|
||||
try:
|
||||
return self.default.__getitem__(item)
|
||||
except KeyError:
|
||||
return item
|
||||
else:
|
||||
return item
|
||||
|
||||
def get(self, *args, **kwargs):
|
||||
res = self.current.get(args[0])
|
||||
|
||||
if res is None:
|
||||
if self.default:
|
||||
return self.default.get(*args, **kwargs)
|
||||
else:
|
||||
return self.current.get(*args, **kwargs)
|
||||
|
||||
return res
|
||||
|
||||
|
||||
def get_available_keys() -> Set[str]:
|
||||
locale_dir = resource.get_path('locale')
|
||||
return {file.split('/')[-1] for file in glob.glob(locale_dir + '/*') if os.path.isfile(file)}
|
||||
|
||||
|
||||
def get_locale_keys(key: str = None, locale_dir: str = resource.get_path('locale')) -> Tuple[str, dict]:
|
||||
|
||||
locale_path = None
|
||||
|
||||
if key is None:
|
||||
try:
|
||||
current_locale = locale.getlocale()
|
||||
|
||||
if current_locale is None or current_locale[0] is None:
|
||||
current_locale = ('en', 'UTF-8')
|
||||
except Exception:
|
||||
current_locale = ('en', 'UTF-8')
|
||||
|
||||
else:
|
||||
current_locale = [key.strip().lower()]
|
||||
|
||||
if current_locale:
|
||||
current_locale = current_locale[0]
|
||||
|
||||
for locale_file in glob.glob(locale_dir + '/*'):
|
||||
name = locale_file.split('/')[-1]
|
||||
|
||||
if current_locale == name or current_locale.startswith(name + '_'):
|
||||
locale_path = locale_file
|
||||
break
|
||||
|
||||
if not locale_path:
|
||||
return current_locale if current_locale else key, {}
|
||||
|
||||
with open(locale_path, 'r') as f:
|
||||
locale_keys = f.readlines()
|
||||
|
||||
locale_obj = {}
|
||||
for line in locale_keys:
|
||||
line_strip = line.strip()
|
||||
if line_strip:
|
||||
try:
|
||||
keyval = line_strip.split('=')
|
||||
locale_obj[keyval[0].strip()] = keyval[1].strip()
|
||||
except Exception:
|
||||
print("Error decoding i18n line '{}'".format(line))
|
||||
|
||||
return locale_path.split('/')[-1], locale_obj
|
||||
@@ -1,88 +0,0 @@
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import traceback
|
||||
from typing import List, Tuple
|
||||
|
||||
from PyQt5.QtCore import QCoreApplication
|
||||
from PyQt5.QtGui import QIcon
|
||||
from colorama import Fore
|
||||
|
||||
from bauh import __app_name__
|
||||
from bauh.api.abstract.controller import SoftwareManager
|
||||
from bauh.api.paths import CONFIG_DIR, CACHE_DIR, TEMP_DIR
|
||||
from bauh.commons.system import run_cmd
|
||||
from bauh.view.util import resource
|
||||
|
||||
|
||||
def notify_user(msg: str, icon_path: str = None):
|
||||
icon_id = icon_path
|
||||
|
||||
if not icon_id:
|
||||
icon_id = get_default_icon()[0]
|
||||
|
||||
os.system("notify-send -a {} {} '{}'".format(__app_name__, "-i {}".format(icon_id) if icon_id else '', msg))
|
||||
|
||||
|
||||
def get_default_icon(system: bool = True) -> Tuple[str, QIcon]:
|
||||
if system:
|
||||
system_icon = QIcon.fromTheme(__app_name__)
|
||||
if not system_icon.isNull():
|
||||
return system_icon.name(), system_icon
|
||||
|
||||
path = resource.get_path('img/logo.svg')
|
||||
return path, QIcon(path)
|
||||
|
||||
|
||||
def restart_app():
|
||||
appimage_path = os.getenv('APPIMAGE')
|
||||
|
||||
restart_cmd = [appimage_path] if appimage_path else [sys.executable, *sys.argv]
|
||||
|
||||
subprocess.Popen(restart_cmd)
|
||||
QCoreApplication.exit()
|
||||
|
||||
|
||||
def get_distro():
|
||||
if os.path.exists('/etc/arch-release'):
|
||||
return 'arch'
|
||||
|
||||
if os.path.exists('/etc/os-release'):
|
||||
with open('/etc/os-release', 'r') as os_release_file:
|
||||
for line in os_release_file:
|
||||
if 'ID_LIKE=arch' in line:
|
||||
return 'arch'
|
||||
|
||||
if os.path.exists('/proc/version'):
|
||||
if 'ubuntu' in run_cmd('cat /proc/version').lower():
|
||||
return 'ubuntu'
|
||||
|
||||
return 'unknown'
|
||||
|
||||
|
||||
def clean_app_files(managers: List[SoftwareManager], logs: bool = True):
|
||||
|
||||
if logs:
|
||||
print('[{}] Cleaning configuration and cache files'.format(__app_name__))
|
||||
|
||||
for path in (CACHE_DIR, CONFIG_DIR, TEMP_DIR):
|
||||
if logs:
|
||||
print('[{}] Deleting directory {}'.format(__app_name__, path))
|
||||
|
||||
if os.path.exists(path):
|
||||
try:
|
||||
shutil.rmtree(path)
|
||||
if logs:
|
||||
print('{}[{}] Directory {} deleted{}'.format(Fore.YELLOW, __app_name__, path, Fore.RESET))
|
||||
except Exception:
|
||||
if logs:
|
||||
print('{}[{}] An exception has happened when deleting {}{}'.format(Fore.RED, __app_name__, path, Fore.RESET))
|
||||
traceback.print_exc()
|
||||
|
||||
if managers:
|
||||
for m in managers:
|
||||
m.clear_data()
|
||||
|
||||
if logs:
|
||||
print('[{}] Cleaning finished'.format(__app_name__))
|
||||
Reference in New Issue
Block a user