improvement -> all suported types now display a 'Checking configuration file' task during the initialization process

This commit is contained in:
Vinicius Moreira
2020-12-30 13:35:15 -03:00
parent 01bd532465
commit c91e982243
69 changed files with 1059 additions and 561 deletions

View File

@@ -59,7 +59,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
<p align="center"> <p align="center">
<img src="https://raw.githubusercontent.com/vinifmor/bauh-files/master/pictures/releases/0.9.11/web_env_exp.png"> <img src="https://raw.githubusercontent.com/vinifmor/bauh-files/master/pictures/releases/0.9.11/web_env_exp.png">
</p> </p>
- displaying the "Indexing suggestions" task during the initialization process
- all types now display an initialization task "Checking configuration file" responsible to create/update the respective configuration file
- minor translation improvements - minor translation improvements

View File

@@ -7,7 +7,7 @@ import urllib3
from PyQt5.QtCore import QCoreApplication, Qt from PyQt5.QtCore import QCoreApplication, Qt
from bauh import __app_name__, app_args from bauh import __app_name__, app_args
from bauh.view.core import config from bauh.view.core.config import CoreConfigManager
from bauh.view.util import logs from bauh.view.util import logs
@@ -25,7 +25,7 @@ def main(tray: bool = False):
if args.offline: if args.offline:
logger.warning("offline mode activated") logger.warning("offline mode activated")
app_config = config.read_config(update_file=True) app_config = CoreConfigManager().get_config()
if bool(app_config['ui']['auto_scale']): if bool(app_config['ui']['auto_scale']):
os.environ['QT_AUTO_SCREEN_SCALE_FACTOR'] = '1' os.environ['QT_AUTO_SCREEN_SCALE_FACTOR'] = '1'

View File

@@ -9,7 +9,8 @@ from bauh.cli import __app_name__, cli_args
from bauh.cli.controller import CLIManager from bauh.cli.controller import CLIManager
from bauh.commons.internet import InternetChecker from bauh.commons.internet import InternetChecker
from bauh.context import generate_i18n, DEFAULT_I18N_KEY from bauh.context import generate_i18n, DEFAULT_I18N_KEY
from bauh.view.core import config, gems from bauh.view.core import gems
from bauh.view.core.config import CoreConfigManager
from bauh.view.core.controller import GenericSoftwareManager from bauh.view.core.controller import GenericSoftwareManager
from bauh.view.core.downloader import AdaptableFileDownloader from bauh.view.core.downloader import AdaptableFileDownloader
from bauh.view.util import logs, util, resource from bauh.view.util import logs, util, resource
@@ -26,7 +27,7 @@ def main():
args = cli_args.read() args = cli_args.read()
logger = logs.new_logger(__app_name__, False) logger = logs.new_logger(__app_name__, False)
app_config = config.read_config(update_file=True) app_config = CoreConfigManager().get_config()
http_client = HttpClient(logger) http_client = HttpClient(logger)
i18n = generate_i18n(app_config, resource.get_path('locale')) i18n = generate_i18n(app_config, resource.get_path('locale'))

57
bauh/commons/boot.py Normal file
View File

@@ -0,0 +1,57 @@
import time
from logging import Logger
from threading import Thread
from typing import Optional
from bauh.api.abstract.handler import TaskManager
from bauh.commons.config import ConfigManager
from bauh.view.util.translation import I18n
class CreateConfigFile(Thread):
"""
Generic initialization task to create a configuration file
"""
def __init__(self, configman: ConfigManager, taskman: TaskManager, task_icon_path: str, i18n: I18n, logger: Logger, config_instance: Optional[dict] = None):
super(CreateConfigFile, self).__init__(daemon=True)
self.configman = configman
self.taskman = taskman
self.logger = logger
self.config = config_instance
self.task_icon_path = task_icon_path
self.task_id = configman.__class__.__name__
self.i18n = i18n
self.task_name = self.i18n['task.checking_config']
self.taskman.register_task(self.task_id, self.task_name, self.task_icon_path)
def _log(self, msg: str):
self.logger.info('{}: {}'.format(self.configman.__class__.__name__, msg))
def run(self):
ti = time.time()
self.taskman.update_progress(self.task_id, 1, None)
self._log("Reading cached configuration file")
default_config = self.configman.get_default_config()
cached_config = self.configman.read_config()
self.taskman.update_progress(self.task_id, 50, None)
if cached_config:
self._log("Merging configuration file")
self.configman.merge_config(default_config, cached_config)
else:
self._log("No cached configuration file found")
self.config = default_config
self.taskman.update_progress(self.task_id, 75, self.i18n['task.checking_config.saving'])
self._log("Writing configuration file")
self.configman.save_config(default_config)
self.taskman.update_progress(self.task_id, 100, None)
self.taskman.finish_task(self.task_id)
tf = time.time()
self._log("Finished. Took {0:.2f} seconds".format(tf - ti))

View File

@@ -18,8 +18,8 @@ from bauh.commons.util import map_timestamp_file
class CategoriesDownloader(Thread): class CategoriesDownloader(Thread):
def __init__(self, id_: str, http_client: HttpClient, logger: logging.Logger, manager: SoftwareManager, def __init__(self, id_: str, http_client: HttpClient, logger: logging.Logger, manager: SoftwareManager,
url_categories_file: str, categories_path: str, expiration: int, internet_checker: InternetChecker, url_categories_file: str, categories_path: str, internet_checker: InternetChecker,
internet_connection: Optional[bool] = True, before=None, after=None): expiration: Optional[int] = None, internet_connection: Optional[bool] = True, before=None, after=None):
""" """
:param id_: :param id_:
:param http_client: :param http_client:
@@ -121,7 +121,7 @@ class CategoriesDownloader(Thread):
self.logger.warning(self._msg("No internet connection. The categories file '{}' cannot be updated.".format(self.categories_path))) self.logger.warning(self._msg("No internet connection. The categories file '{}' cannot be updated.".format(self.categories_path)))
return False return False
if self.expiration <= 0: if self.expiration is None or self.expiration <= 0:
self.logger.warning(self._msg("No expiration set for the categories file '{}'. It should be downloaded".format(self.categories_path))) self.logger.warning(self._msg("No expiration set for the categories file '{}'. It should be downloaded".format(self.categories_path)))
return True return True

View File

@@ -1,6 +1,9 @@
import os import os
import traceback
from abc import abstractmethod, ABC
from pathlib import Path from pathlib import Path
from threading import Thread from threading import Thread
from typing import Optional
import yaml import yaml
@@ -31,3 +34,69 @@ def read_config(file_path: str, template: dict, update_file: bool = False, updat
def save_config(config: dict, file_path: str): def save_config(config: dict, file_path: str):
with open(file_path, 'w+') as f: with open(file_path, 'w+') as f:
f.write(yaml.dump(config)) f.write(yaml.dump(config))
class ConfigManager(ABC):
@abstractmethod
def read_config(self) -> Optional[dict]:
pass
@abstractmethod
def get_default_config(self) -> dict:
pass
@abstractmethod
def is_config_cached(self) -> bool:
pass
def get_config(self) -> dict:
default_config = self.get_default_config()
if default_config:
cached_config = self.read_config()
if cached_config:
self.merge_config(default_config, cached_config)
return default_config
@staticmethod
def merge_config(base_config: dict, current_config: dict):
util.deep_update(base_config, current_config)
@abstractmethod
def save_config(self, config_obj: dict):
pass
class YAMLConfigManager(ConfigManager, ABC):
def __init__(self, config_file_path: str):
self.file_path = config_file_path
def is_config_cached(self) -> bool:
return os.path.exists(self.file_path)
def read_config(self) -> Optional[dict]:
if self.is_config_cached():
with open(self.file_path) as f:
local_config = yaml.safe_load(f.read())
if local_config is not None:
return local_config
def save_config(self, config_obj: dict):
if config_obj:
config_dir = os.path.dirname(self.file_path)
try:
Path(config_dir).mkdir(parents=True, exist_ok=True)
except OSError:
traceback.print_exc()
return
try:
with open(self.file_path, 'w+') as f:
f.write(yaml.dump(config_obj))
except:
traceback.print_exc()

View File

@@ -1,11 +1,15 @@
from bauh.commons.config import read_config as read from bauh.commons.config import YAMLConfigManager
from bauh.gems.appimage import CONFIG_FILE from bauh.gems.appimage import CONFIG_FILE
def read_config(update_file: bool = False) -> dict: class AppImageConfigManager(YAMLConfigManager):
default = {
'database': { def __init__(self):
'expiration': 60 super(AppImageConfigManager, self).__init__(config_file_path=CONFIG_FILE)
def get_default_config(self) -> dict:
return {
'database': {
'expiration': 60
}
} }
}
return read(CONFIG_FILE, default, update_file=update_file)

View File

@@ -24,13 +24,13 @@ from bauh.api.abstract.model import SoftwarePackage, PackageHistory, PackageUpda
from bauh.api.abstract.view import MessageType, ViewComponent, FormComponent, InputOption, SingleSelectComponent, \ from bauh.api.abstract.view import MessageType, ViewComponent, FormComponent, InputOption, SingleSelectComponent, \
SelectViewType, TextInputComponent, PanelComponent, FileChooserComponent, ViewObserver SelectViewType, TextInputComponent, PanelComponent, FileChooserComponent, ViewObserver
from bauh.commons import resource from bauh.commons import resource
from bauh.commons.config import save_config from bauh.commons.boot import CreateConfigFile
from bauh.commons.html import bold from bauh.commons.html import bold
from bauh.commons.system import SystemProcess, new_subprocess, ProcessHandler, run_cmd, SimpleProcess from bauh.commons.system import SystemProcess, new_subprocess, ProcessHandler, run_cmd, SimpleProcess
from bauh.gems.appimage import query, INSTALLATION_PATH, LOCAL_PATH, SUGGESTIONS_FILE, CONFIG_FILE, ROOT_DIR, \ from bauh.gems.appimage import query, INSTALLATION_PATH, LOCAL_PATH, SUGGESTIONS_FILE, ROOT_DIR, \
CONFIG_DIR, UPDATES_IGNORED_FILE, util, get_default_manual_installation_file_dir, DATABASE_APPS_FILE, \ CONFIG_DIR, UPDATES_IGNORED_FILE, util, get_default_manual_installation_file_dir, DATABASE_APPS_FILE, \
DATABASE_RELEASES_FILE, DESKTOP_ENTRIES_PATH, DATABASES_DIR DATABASE_RELEASES_FILE, DESKTOP_ENTRIES_PATH, DATABASES_DIR, get_icon_path
from bauh.gems.appimage.config import read_config from bauh.gems.appimage.config import AppImageConfigManager
from bauh.gems.appimage.model import AppImage from bauh.gems.appimage.model import AppImage
from bauh.gems.appimage.util import replace_desktop_entry_exec_command from bauh.gems.appimage.util import replace_desktop_entry_exec_command
from bauh.gems.appimage.worker import DatabaseUpdater, SymlinksVerifier from bauh.gems.appimage.worker import DatabaseUpdater, SymlinksVerifier
@@ -76,6 +76,7 @@ class AppImageManager(SoftwareManager):
self.http_client = context.http_client self.http_client = context.http_client
self.logger = context.logger self.logger = context.logger
self.file_downloader = context.file_downloader self.file_downloader = context.file_downloader
self.configman = AppImageConfigManager()
self.custom_actions = [CustomSoftwareAction(i18n_label_key='appimage.custom_action.install_file', self.custom_actions = [CustomSoftwareAction(i18n_label_key='appimage.custom_action.install_file',
i18n_status_key='appimage.custom_action.install_file.status', i18n_status_key='appimage.custom_action.install_file.status',
manager=self, manager=self,
@@ -616,16 +617,17 @@ class AppImageManager(SoftwareManager):
return False return False
def prepare(self, task_manager: TaskManager, root_password: str, internet_available: bool): def prepare(self, task_manager: TaskManager, root_password: str, internet_available: bool):
create_config = CreateConfigFile(taskman=task_manager, configman=self.configman, i18n=self.i18n,
task_icon_path=get_icon_path(), logger=self.logger)
create_config.start()
symlink_check = SymlinksVerifier(taskman=task_manager, i18n=self.i18n, logger=self.logger) symlink_check = SymlinksVerifier(taskman=task_manager, i18n=self.i18n, logger=self.logger)
symlink_check.start() symlink_check.start()
if internet_available: if internet_available:
updater = DatabaseUpdater(taskman=task_manager, i18n=self.context.i18n, DatabaseUpdater(taskman=task_manager, i18n=self.context.i18n,
http_client=self.context.http_client, logger=self.context.logger) create_config=create_config, http_client=self.context.http_client,
logger=self.context.logger).start()
if updater.should_update(read_config()):
updater.register_task()
updater.start()
def list_updates(self, internet_available: bool) -> List[PackageUpdate]: def list_updates(self, internet_available: bool) -> List[PackageUpdate]:
res = self.read_installed(disk_loader=None, internet_available=internet_available) res = self.read_installed(disk_loader=None, internet_available=internet_available)
@@ -729,12 +731,12 @@ class AppImageManager(SoftwareManager):
traceback.print_exc() traceback.print_exc()
def get_settings(self, screen_width: int, screen_height: int) -> ViewComponent: def get_settings(self, screen_width: int, screen_height: int) -> ViewComponent:
config = read_config() appimage_config = self.configman.get_config()
max_width = floor(screen_width * 0.15) max_width = floor(screen_width * 0.15)
opts = [ opts = [
TextInputComponent(label=self.i18n['appimage.config.database.expiration'], TextInputComponent(label=self.i18n['appimage.config.database.expiration'],
value=int(config['database']['expiration']) if isinstance(config['database']['expiration'], int) else '', value=int(appimage_config['database']['expiration']) if isinstance(appimage_config['database']['expiration'], int) else '',
tooltip=self.i18n['appimage.config.database.expiration.tip'], tooltip=self.i18n['appimage.config.database.expiration.tip'],
only_int=True, only_int=True,
max_width=max_width, max_width=max_width,
@@ -744,13 +746,13 @@ class AppImageManager(SoftwareManager):
return PanelComponent([FormComponent(opts, self.i18n['appimage.config.database'])]) return PanelComponent([FormComponent(opts, self.i18n['appimage.config.database'])])
def save_settings(self, component: PanelComponent) -> Tuple[bool, Optional[List[str]]]: def save_settings(self, component: PanelComponent) -> Tuple[bool, Optional[List[str]]]:
config = read_config() appimage_config = self.configman.get_config()
panel = component.components[0] panel = component.components[0]
config['database']['expiration'] = panel.get_component('appim_db_exp').get_int_value() appimage_config['database']['expiration'] = panel.get_component('appim_db_exp').get_int_value()
try: try:
save_config(config, CONFIG_FILE) self.configman.save_config(appimage_config)
return True, None return True, None
except: except:
return False, [traceback.format_exc()] return False, [traceback.format_exc()]
@@ -822,7 +824,7 @@ class AppImageManager(SoftwareManager):
def update_database(self, root_password: str, watcher: ProcessWatcher) -> bool: def update_database(self, root_password: str, watcher: ProcessWatcher) -> bool:
db_updater = DatabaseUpdater(i18n=self.i18n, http_client=self.context.http_client, db_updater = DatabaseUpdater(i18n=self.i18n, http_client=self.context.http_client,
logger=self.context.logger, watcher=watcher) logger=self.context.logger, watcher=watcher, taskman=TaskManager())
res = db_updater.download_databases() res = db_updater.download_databases()
return res return res

View File

@@ -36,6 +36,7 @@ appimage.update_database.deleting_old=Removing old files
appimage.update_database.downloading=Downloading database files appimage.update_database.downloading=Downloading database files
appimage.update_database.uncompressing=Uncompressing files appimage.update_database.uncompressing=Uncompressing files
appimage.task.db_update=Actualització de bases de dades appimage.task.db_update=Actualització de bases de dades
appimage.task.db_update.checking=Checking for updates
appimage.task.symlink_check=Checking symlinks appimage.task.symlink_check=Checking symlinks
appimage.uninstall.error.remove_folder=No sha pogut suprimir el directori dinstal·lació de laplicació {} appimage.uninstall.error.remove_folder=No sha pogut suprimir el directori dinstal·lació de laplicació {}
appimage.warning.missing_db_files={appimage} database files were not found. Some actions will not work properly. appimage.warning.missing_db_files={appimage} database files were not found. Some actions will not work properly.

View File

@@ -36,6 +36,7 @@ appimage.update_database.deleting_old=Removing old files
appimage.update_database.downloading=Downloading database files appimage.update_database.downloading=Downloading database files
appimage.update_database.uncompressing=Uncompressing files appimage.update_database.uncompressing=Uncompressing files
appimage.task.db_update=Updating databases appimage.task.db_update=Updating databases
appimage.task.db_update.checking=Checking for updates
appimage.task.symlink_check=Checking symlinks appimage.task.symlink_check=Checking symlinks
appimage.uninstall.error.remove_folder=Anwendungordner {} konnte nicht entfernt werden appimage.uninstall.error.remove_folder=Anwendungordner {} konnte nicht entfernt werden
appimage.warning.missing_db_files={appimage} database files were not found. Some actions will not work properly. appimage.warning.missing_db_files={appimage} database files were not found. Some actions will not work properly.

View File

@@ -1,6 +1,6 @@
appimage.config.database=Database appimage.config.database=Database
appimage.config.database.expiration=Expiration appimage.config.database.expiration=Expiration
appimage.config.database.expiration.tip=appimage.config.database.expiration.tip=It defines the period (in minutes) in which the database will be considered up to date. Use 0 if you always want to update it. appimage.config.database.expiration.tip=It defines the period (in minutes) in which the database will be considered up to date. Use 0 if you always want to update it.
appimage.custom_action.install_file=Install AppImage file appimage.custom_action.install_file=Install AppImage file
appimage.custom_action.install_file.details=Installation details appimage.custom_action.install_file.details=Installation details
appimage.custom_action.install_file.invalid_file=You must define a valid AppImage file appimage.custom_action.install_file.invalid_file=You must define a valid AppImage file
@@ -36,6 +36,7 @@ appimage.update_database.deleting_old=Removing old files
appimage.update_database.downloading=Downloading database files appimage.update_database.downloading=Downloading database files
appimage.update_database.uncompressing=Uncompressing files appimage.update_database.uncompressing=Uncompressing files
appimage.task.db_update=Updating databases appimage.task.db_update=Updating databases
appimage.task.db_update.checking=Checking for updates
appimage.task.symlink_check=Checking symlinks appimage.task.symlink_check=Checking symlinks
appimage.uninstall.error.remove_folder=Could not remove the application installation directory {} appimage.uninstall.error.remove_folder=Could not remove the application installation directory {}
appimage.warning.missing_db_files={appimage} database files were not found. Some actions will not work properly. appimage.warning.missing_db_files={appimage} database files were not found. Some actions will not work properly.

View File

@@ -36,6 +36,7 @@ appimage.update_database.deleting_old=Eliminando archivos antiguos
appimage.update_database.downloading=Descargando archivos de la base de datos appimage.update_database.downloading=Descargando archivos de la base de datos
appimage.update_database.uncompressing=Descomprindo archivos appimage.update_database.uncompressing=Descomprindo archivos
appimage.task.db_update=Actualizando base de datos appimage.task.db_update=Actualizando base de datos
appimage.task.db_update.checking=Buscando actualizaciones
appimage.task.symlink_check=Verificando links simbólicos appimage.task.symlink_check=Verificando links simbólicos
appimage.uninstall.error.remove_folder=No se pudo eliminar el directorio de instalación de la aplicación {} appimage.uninstall.error.remove_folder=No se pudo eliminar el directorio de instalación de la aplicación {}
appimage.warning.missing_db_files=No se encontraron archivos de la base de datos {appimage}. Algunas acciones no funcionarán correctamente. appimage.warning.missing_db_files=No se encontraron archivos de la base de datos {appimage}. Algunas acciones no funcionarán correctamente.

View File

@@ -36,6 +36,7 @@ appimage.update_database.deleting_old=Removing old files
appimage.update_database.downloading=Downloading database files appimage.update_database.downloading=Downloading database files
appimage.update_database.uncompressing=Uncompressing files appimage.update_database.uncompressing=Uncompressing files
appimage.task.db_update=Mise à jour des bases de données appimage.task.db_update=Mise à jour des bases de données
appimage.task.db_update.checking=Checking for updates
appimage.task.symlink_check=Verification des symlinks appimage.task.symlink_check=Verification des symlinks
appimage.uninstall.error.remove_folder=Impossible de supprimer le répertoire d'installation {} appimage.uninstall.error.remove_folder=Impossible de supprimer le répertoire d'installation {}
appimage.warning.missing_db_files={appimage} database files were not found. Some actions will not work properly. appimage.warning.missing_db_files={appimage} database files were not found. Some actions will not work properly.

View File

@@ -36,6 +36,7 @@ appimage.update_database.deleting_old=Removing old files
appimage.update_database.downloading=Downloading database files appimage.update_database.downloading=Downloading database files
appimage.update_database.uncompressing=Uncompressing files appimage.update_database.uncompressing=Uncompressing files
appimage.task.db_update=Aggiornamento dei database appimage.task.db_update=Aggiornamento dei database
appimage.task.db_update.checking=Checking for updates
appimage.task.symlink_check=Checking symlinks appimage.task.symlink_check=Checking symlinks
appimage.uninstall.error.remove_folder=Impossibile rimuovere la directory di installazione dell'applicazione {} appimage.uninstall.error.remove_folder=Impossibile rimuovere la directory di installazione dell'applicazione {}
appimage.warning.missing_db_files={appimage} database files were not found. Some actions will not work properly. appimage.warning.missing_db_files={appimage} database files were not found. Some actions will not work properly.

View File

@@ -36,6 +36,7 @@ appimage.update_database.deleting_old=Removendo arquicos antigos
appimage.update_database.downloading=Baixando arquivos do banco de dados appimage.update_database.downloading=Baixando arquivos do banco de dados
appimage.update_database.uncompressing=Descomprimindo arquivos appimage.update_database.uncompressing=Descomprimindo arquivos
appimage.task.db_update=Atualizando base de dados appimage.task.db_update=Atualizando base de dados
appimage.task.db_update.checking=Checando atualizações
appimage.task.symlink_check=Verificando links simbólicos appimage.task.symlink_check=Verificando links simbólicos
appimage.uninstall.error.remove_folder=Não foi possível remover o diretóri ode instalação do aplicativo {} appimage.uninstall.error.remove_folder=Não foi possível remover o diretóri ode instalação do aplicativo {}
appimage.warning.missing_db_files=Arquivos do banco de dados {appimage} não foram encontrados. Algumas ações não funcionarão corretamente. appimage.warning.missing_db_files=Arquivos do banco de dados {appimage} não foram encontrados. Algumas ações não funcionarão corretamente.

View File

@@ -36,6 +36,7 @@ appimage.update_database.deleting_old=Removing old files
appimage.update_database.downloading=Downloading database files appimage.update_database.downloading=Downloading database files
appimage.update_database.uncompressing=Uncompressing files appimage.update_database.uncompressing=Uncompressing files
appimage.task.db_update=Обновление базы данных appimage.task.db_update=Обновление базы данных
appimage.task.db_update.checking=Checking for updates
appimage.task.symlink_check=Checking symlinks appimage.task.symlink_check=Checking symlinks
appimage.uninstall.error.remove_folder=Не удалось удалить каталог приложения {} appimage.uninstall.error.remove_folder=Не удалось удалить каталог приложения {}
appimage.warning.missing_db_files={appimage} database files were not found. Some actions will not work properly. appimage.warning.missing_db_files={appimage} database files were not found. Some actions will not work properly.

View File

@@ -36,6 +36,7 @@ appimage.update_database.deleting_old=Removing old files
appimage.update_database.downloading=Downloading database files appimage.update_database.downloading=Downloading database files
appimage.update_database.uncompressing=Uncompressing files appimage.update_database.uncompressing=Uncompressing files
appimage.task.db_update=Veritabanları güncelleniyor appimage.task.db_update=Veritabanları güncelleniyor
appimage.task.db_update.checking=Checking for updates
appimage.task.symlink_check=Checking symlinks appimage.task.symlink_check=Checking symlinks
appimage.uninstall.error.remove_folder={} uygulama kurulum dizini kaldırılamadı appimage.uninstall.error.remove_folder={} uygulama kurulum dizini kaldırılamadı
appimage.warning.missing_db_files={appimage} database files were not found. Some actions will not work properly. appimage.warning.missing_db_files={appimage} database files were not found. Some actions will not work properly.

View File

@@ -12,6 +12,8 @@ from typing import Optional
from bauh.api.abstract.handler import TaskManager, ProcessWatcher from bauh.api.abstract.handler import TaskManager, ProcessWatcher
from bauh.api.http import HttpClient from bauh.api.http import HttpClient
from bauh.commons.boot import CreateConfigFile
from bauh.commons.html import bold
from bauh.gems.appimage import get_icon_path, INSTALLATION_PATH, SYMLINKS_DIR, util, DATABASES_TS_FILE, \ from bauh.gems.appimage import get_icon_path, INSTALLATION_PATH, SYMLINKS_DIR, util, DATABASES_TS_FILE, \
DATABASES_DIR, DATABASE_APPS_FILE, DATABASE_RELEASES_FILE, URL_COMPRESSED_DATABASES DATABASES_DIR, DATABASE_APPS_FILE, DATABASE_RELEASES_FILE, URL_COMPRESSED_DATABASES
from bauh.gems.appimage.model import AppImage from bauh.gems.appimage.model import AppImage
@@ -21,7 +23,8 @@ from bauh.view.util.translation import I18n
class DatabaseUpdater(Thread): class DatabaseUpdater(Thread):
COMPRESS_FILE_PATH = '{}/db.tar.gz'.format(DATABASES_DIR) COMPRESS_FILE_PATH = '{}/db.tar.gz'.format(DATABASES_DIR)
def __init__(self, i18n: I18n, http_client: HttpClient, logger: logging.Logger, watcher: Optional[ProcessWatcher] = None, taskman: Optional[TaskManager] = None): def __init__(self, i18n: I18n, http_client: HttpClient, logger: logging.Logger, taskman: TaskManager,
watcher: Optional[ProcessWatcher] = None, appimage_config: Optional[dict] = None, create_config: Optional[CreateConfigFile] = None):
super(DatabaseUpdater, self).__init__(daemon=True) super(DatabaseUpdater, self).__init__(daemon=True)
self.http_client = http_client self.http_client = http_client
self.logger = logger self.logger = logger
@@ -29,6 +32,9 @@ class DatabaseUpdater(Thread):
self.taskman = taskman self.taskman = taskman
self.watcher = watcher self.watcher = watcher
self.task_id = 'appim_db' self.task_id = 'appim_db'
self.config = appimage_config
self.create_config = create_config
self.taskman.register_task(self.task_id, self.i18n['appimage.task.db_update'], get_icon_path())
def should_update(self, appimage_config: dict) -> bool: def should_update(self, appimage_config: dict) -> bool:
ti = time.time() ti = time.time()
@@ -75,26 +81,14 @@ class DatabaseUpdater(Thread):
self.logger.info('Finished. Took {0:.2f} seconds'.format(time.time() - ti)) self.logger.info('Finished. Took {0:.2f} seconds'.format(time.time() - ti))
return update return update
def register_task(self):
if self.taskman:
self.taskman.register_task(self.task_id, self.i18n['appimage.task.db_update'], get_icon_path())
def _finish_task(self):
if self.taskman:
self.taskman.update_progress(self.task_id, 100, None)
self.taskman.finish_task(self.task_id)
self.taskman = None
self.logger.info("Finished")
def _update_task_progress(self, progress: float, substatus: Optional[str] = None): def _update_task_progress(self, progress: float, substatus: Optional[str] = None):
if self.taskman: self.taskman.update_progress(self.task_id, progress, substatus)
self.taskman.update_progress(self.task_id, progress, substatus)
if self.watcher: if self.watcher:
self.watcher.change_substatus(substatus) self.watcher.change_substatus(substatus)
def download_databases(self) -> bool: def download_databases(self) -> bool:
self._update_task_progress(1, self.i18n['appimage.update_database.downloading']) self._update_task_progress(10, self.i18n['appimage.update_database.downloading'])
self.logger.info('Retrieving AppImage databases') self.logger.info('Retrieving AppImage databases')
database_timestamp = datetime.utcnow().timestamp() database_timestamp = datetime.utcnow().timestamp()
@@ -106,7 +100,6 @@ class DatabaseUpdater(Thread):
if not res: if not res:
self.logger.warning('Could not download the database file {}'.format(URL_COMPRESSED_DATABASES)) self.logger.warning('Could not download the database file {}'.format(URL_COMPRESSED_DATABASES))
self._finish_task()
return False return False
Path(DATABASES_DIR).mkdir(parents=True, exist_ok=True) Path(DATABASES_DIR).mkdir(parents=True, exist_ok=True)
@@ -150,11 +143,25 @@ class DatabaseUpdater(Thread):
self.logger.info("Database timestamp saved") self.logger.info("Database timestamp saved")
self._finish_task()
return True return True
def run(self): def run(self):
self.download_databases() ti = time.time()
if self.create_config:
self.taskman.update_progress(self.task_id, 0, self.i18n['task.waiting_task'].format(bold(self.create_config.task_name)))
self.create_config.join()
self.config = self.create_config.config
self.taskman.update_progress(self.task_id, 1, self.i18n['appimage.task.db_update.checking'])
if self.should_update(self.config):
self.download_databases()
self.taskman.update_progress(self.task_id, 100, None)
self.taskman.finish_task(self.task_id)
tf = time.time()
self.logger.info("Finished. Took {0:.2f} seconds".format(tf - ti))
class SymlinksVerifier(Thread): class SymlinksVerifier(Thread):
@@ -165,6 +172,7 @@ class SymlinksVerifier(Thread):
self.i18n = i18n self.i18n = i18n
self.logger = logger self.logger = logger
self.task_id = 'appim_symlink_check' self.task_id = 'appim_symlink_check'
self.taskman.register_task(self.task_id, self.i18n['appimage.task.symlink_check'], get_icon_path())
@staticmethod @staticmethod
def create_symlink(app: AppImage, file_path: str, logger: logging.Logger, watcher: ProcessWatcher = None): def create_symlink(app: AppImage, file_path: str, logger: logging.Logger, watcher: ProcessWatcher = None):
@@ -222,8 +230,6 @@ class SymlinksVerifier(Thread):
watcher.print('[error] {}'.format(msg)) watcher.print('[error] {}'.format(msg))
def run(self): def run(self):
self.taskman.register_task(self.task_id, self.i18n['appimage.task.symlink_check'], get_icon_path())
if os.path.exists(INSTALLATION_PATH): if os.path.exists(INSTALLATION_PATH):
installed_files = glob.glob('{}/*/*.json'.format(INSTALLATION_PATH)) installed_files = glob.glob('{}/*/*.json'.format(INSTALLATION_PATH))

View File

@@ -1,11 +1,26 @@
from pathlib import Path from pathlib import Path
from bauh.commons.config import read_config as read from bauh.commons.config import YAMLConfigManager
from bauh.gems.arch import CONFIG_FILE, BUILD_DIR from bauh.gems.arch import CONFIG_FILE, BUILD_DIR
def read_config(update_file: bool = False) -> dict: def get_build_dir(arch_config: dict) -> str:
template = {'optimize': True, build_dir = arch_config.get('aur_build_dir')
if not build_dir:
build_dir = BUILD_DIR
Path(build_dir).mkdir(parents=True, exist_ok=True)
return build_dir
class ArchConfigManager(YAMLConfigManager):
def __init__(self):
super(ArchConfigManager, self).__init__(config_file_path=CONFIG_FILE)
def get_default_config(self) -> dict:
return {'optimize': True,
"sync_databases": True, "sync_databases": True,
"clean_cached": True, "clean_cached": True,
'aur': True, 'aur': True,
@@ -24,14 +39,3 @@ def read_config(update_file: bool = False) -> dict:
'suggest_optdep_uninstall': False, 'suggest_optdep_uninstall': False,
'aur_idx_exp': 720, 'aur_idx_exp': 720,
'categories_exp': 24} 'categories_exp': 24}
return read(CONFIG_FILE, template, update_file=update_file)
def get_build_dir(arch_config: dict) -> str:
build_dir = arch_config.get('aur_build_dir')
if not build_dir:
build_dir = BUILD_DIR
Path(build_dir).mkdir(parents=True, exist_ok=True)
return build_dir

View File

@@ -27,18 +27,18 @@ from bauh.api.abstract.view import MessageType, FormComponent, InputOption, Sing
FileChooserComponent, TextComponent FileChooserComponent, TextComponent
from bauh.api.constants import TEMP_DIR from bauh.api.constants import TEMP_DIR
from bauh.commons import user, system from bauh.commons import user, system
from bauh.commons.boot import CreateConfigFile
from bauh.commons.category import CategoriesDownloader from bauh.commons.category import CategoriesDownloader
from bauh.commons.config import save_config
from bauh.commons.html import bold from bauh.commons.html import bold
from bauh.commons.system import SystemProcess, ProcessHandler, new_subprocess, run_cmd, SimpleProcess from bauh.commons.system import SystemProcess, ProcessHandler, new_subprocess, run_cmd, SimpleProcess
from bauh.commons.util import datetime_as_milis from bauh.commons.util import datetime_as_milis
from bauh.commons.view_utils import new_select from bauh.commons.view_utils import new_select
from bauh.gems.arch import aur, pacman, makepkg, message, confirmation, disk, git, \ from bauh.gems.arch import aur, pacman, makepkg, message, confirmation, disk, git, \
gpg, URL_CATEGORIES_FILE, CATEGORIES_FILE_PATH, CUSTOM_MAKEPKG_FILE, SUGGESTIONS_FILE, \ gpg, URL_CATEGORIES_FILE, CATEGORIES_FILE_PATH, CUSTOM_MAKEPKG_FILE, SUGGESTIONS_FILE, \
CONFIG_FILE, get_icon_path, database, mirrors, sorting, cpu_manager, ARCH_CACHE_PATH, UPDATES_IGNORED_FILE, \ get_icon_path, database, mirrors, sorting, cpu_manager, UPDATES_IGNORED_FILE, \
CONFIG_DIR, EDITABLE_PKGBUILDS_FILE, URL_GPG_SERVERS, BUILD_DIR CONFIG_DIR, EDITABLE_PKGBUILDS_FILE, URL_GPG_SERVERS, BUILD_DIR
from bauh.gems.arch.aur import AURClient from bauh.gems.arch.aur import AURClient
from bauh.gems.arch.config import read_config, get_build_dir from bauh.gems.arch.config import get_build_dir, ArchConfigManager
from bauh.gems.arch.dependencies import DependenciesAnalyser from bauh.gems.arch.dependencies import DependenciesAnalyser
from bauh.gems.arch.download import MultithreadedDownloadService, ArchDownloadException from bauh.gems.arch.download import MultithreadedDownloadService, ArchDownloadException
from bauh.gems.arch.exceptions import PackageNotFoundException, PackageInHoldException from bauh.gems.arch.exceptions import PackageNotFoundException, PackageInHoldException
@@ -47,8 +47,8 @@ from bauh.gems.arch.model import ArchPackage
from bauh.gems.arch.output import TransactionStatusHandler from bauh.gems.arch.output import TransactionStatusHandler
from bauh.gems.arch.pacman import RE_DEP_OPERATORS from bauh.gems.arch.pacman import RE_DEP_OPERATORS
from bauh.gems.arch.updates import UpdatesSummarizer from bauh.gems.arch.updates import UpdatesSummarizer
from bauh.gems.arch.worker import AURIndexUpdater, ArchDiskCacheUpdater, ArchCompilationOptimizer, SyncDatabases, \ from bauh.gems.arch.worker import AURIndexUpdater, ArchDiskCacheUpdater, ArchCompilationOptimizer, RefreshMirrors, \
RefreshMirrors SyncDatabases
URL_GIT = 'https://aur.archlinux.org/{}.git' URL_GIT = 'https://aur.archlinux.org/{}.git'
URL_SRC_INFO = 'https://aur.archlinux.org/cgit/aur.git/plain/.SRCINFO?h=' URL_SRC_INFO = 'https://aur.archlinux.org/cgit/aur.git/plain/.SRCINFO?h='
@@ -191,11 +191,11 @@ class TransactionContext:
class ArchManager(SoftwareManager): class ArchManager(SoftwareManager):
def __init__(self, context: ApplicationContext, disk_cache_updater: ArchDiskCacheUpdater = None): def __init__(self, context: ApplicationContext, disk_cache_updater: Optional[ArchDiskCacheUpdater] = None):
super(ArchManager, self).__init__(context=context) super(ArchManager, self).__init__(context=context)
self.aur_cache = context.cache_factory.new() self.aur_cache = context.cache_factory.new()
# context.disk_loader_factory.map(ArchPackage, self.aur_cache) TODO # context.disk_loader_factory.map(ArchPackage, self.aur_cache) TODO
self.configman = ArchConfigManager()
self.aur_mapper = AURDataMapper(http_client=context.http_client, i18n=context.i18n, logger=context.logger) self.aur_mapper = AURDataMapper(http_client=context.http_client, i18n=context.i18n, logger=context.logger)
self.i18n = context.i18n self.i18n = context.i18n
self.aur_client = AURClient(http_client=context.http_client, logger=context.logger, x86_64=context.is_system_x86_64()) self.aur_client = AURClient(http_client=context.http_client, logger=context.logger, x86_64=context.is_system_x86_64())
@@ -309,7 +309,7 @@ class ArchManager(SoftwareManager):
type_=MessageType.ERROR) type_=MessageType.ERROR)
return False return False
sort_limit = read_config()['mirrors_sort_limit'] sort_limit = self.configman.get_config()['mirrors_sort_limit']
if sort_limit is not None and isinstance(sort_limit, int) and sort_limit >= 0: if sort_limit is not None and isinstance(sort_limit, int) and sort_limit >= 0:
watcher.change_substatus(self.i18n['arch.custom_action.refresh_mirrors.status.sorting']) watcher.change_substatus(self.i18n['arch.custom_action.refresh_mirrors.status.sorting'])
@@ -419,7 +419,7 @@ class ArchManager(SoftwareManager):
if is_url: if is_url:
return SearchResult([], [], 0) return SearchResult([], [], 0)
arch_config = read_config() arch_config = self.configman.get_config()
aur_supported = aur.is_supported(arch_config) aur_supported = aur.is_supported(arch_config)
if not any([arch_config['repositories'], aur_supported]): if not any([arch_config['repositories'], aur_supported]):
@@ -563,7 +563,7 @@ class ArchManager(SoftwareManager):
def read_installed(self, disk_loader: Optional[DiskCacheLoader], limit: int = -1, only_apps: bool = False, pkg_types: Set[Type[SoftwarePackage]] = None, internet_available: bool = None, names: Iterable[str] = None, wait_disk_cache: bool = True) -> SearchResult: def read_installed(self, disk_loader: Optional[DiskCacheLoader], limit: int = -1, only_apps: bool = False, pkg_types: Set[Type[SoftwarePackage]] = None, internet_available: bool = None, names: Iterable[str] = None, wait_disk_cache: bool = True) -> SearchResult:
self.aur_client.clean_caches() self.aur_client.clean_caches()
arch_config = read_config() arch_config = self.configman.get_config()
aur_supported = aur.is_supported(arch_config) aur_supported = aur.is_supported(arch_config)
@@ -781,7 +781,7 @@ class ArchManager(SoftwareManager):
if self._is_database_locked(handler, root_password): if self._is_database_locked(handler, root_password):
return False return False
arch_config = read_config() arch_config = self.configman.get_config()
aur_supported = pkg.repository == 'aur' or aur.is_supported(arch_config) aur_supported = pkg.repository == 'aur' or aur.is_supported(arch_config)
context = TransactionContext(name=pkg.name, base=pkg.get_base_name(), skip_opt_deps=True, context = TransactionContext(name=pkg.name, base=pkg.get_base_name(), skip_opt_deps=True,
change_progress=True, dependency=False, repository=pkg.repository, pkg=pkg, change_progress=True, dependency=False, repository=pkg.repository, pkg=pkg,
@@ -1105,7 +1105,7 @@ class ArchManager(SoftwareManager):
if aur_pkgs and not self._check_action_allowed(aur_pkgs[0], watcher): if aur_pkgs and not self._check_action_allowed(aur_pkgs[0], watcher):
return False return False
arch_config = read_config() arch_config = self.configman.get_config()
aur_supported = bool(aur_pkgs) or aur.is_supported(arch_config) aur_supported = bool(aur_pkgs) or aur.is_supported(arch_config)
self._sync_databases(arch_config=arch_config, aur_supported=aur_supported, self._sync_databases(arch_config=arch_config, aur_supported=aur_supported,
@@ -1392,7 +1392,7 @@ class ArchManager(SoftwareManager):
return TransactionResult.fail() return TransactionResult.fail()
removed = {} removed = {}
arch_config = read_config() arch_config = self.configman.get_config()
success = self._uninstall(TransactionContext(change_progress=True, success = self._uninstall(TransactionContext(change_progress=True,
arch_config=arch_config, arch_config=arch_config,
watcher=watcher, watcher=watcher,
@@ -1520,7 +1520,7 @@ class ArchManager(SoftwareManager):
else: else:
self.logger.warning("Package '{}' has no commit associated with it. Current history status may not be correct.".format(pkg.name)) self.logger.warning("Package '{}' has no commit associated with it. Current history status may not be correct.".format(pkg.name))
arch_config = read_config() arch_config = self.configman.get_config()
temp_dir = '{}/build_{}'.format(get_build_dir(arch_config), int(time.time())) temp_dir = '{}/build_{}'.format(get_build_dir(arch_config), int(time.time()))
try: try:
@@ -1938,7 +1938,7 @@ class ArchManager(SoftwareManager):
watcher.change_substatus(self.i18n['arch.task.aur.index.status']) watcher.change_substatus(self.i18n['arch.task.aur.index.status'])
idx_updater = AURIndexUpdater(context=self.context, taskman=TaskManager()) # null task manager idx_updater = AURIndexUpdater(context=self.context, taskman=TaskManager()) # null task manager
idx_updater.run() idx_updater.update_index()
else: else:
self.logger.warning("Could not update the AUR index: no internet connection detected") self.logger.warning("Could not update the AUR index: no internet connection detected")
@@ -2488,7 +2488,7 @@ class ArchManager(SoftwareManager):
def _optimize_makepkg(self, arch_config: dict, watcher: Optional[ProcessWatcher]): def _optimize_makepkg(self, arch_config: dict, watcher: Optional[ProcessWatcher]):
if arch_config['optimize'] and not os.path.exists(CUSTOM_MAKEPKG_FILE): if arch_config['optimize'] and not os.path.exists(CUSTOM_MAKEPKG_FILE):
watcher.change_substatus(self.i18n['arch.makepkg.optimizing']) watcher.change_substatus(self.i18n['arch.makepkg.optimizing'])
ArchCompilationOptimizer(arch_config=arch_config, i18n=self.i18n, logger=self.context.logger).optimize() ArchCompilationOptimizer(i18n=self.i18n, logger=self.context.logger, taskman=TaskManager()).optimize()
def install(self, pkg: ArchPackage, root_password: str, disk_loader: Optional[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() self.aur_client.clean_caches()
@@ -2504,7 +2504,7 @@ class ArchManager(SoftwareManager):
if context: if context:
install_context = context install_context = context
else: else:
install_context = TransactionContext.gen_context_from(pkg=pkg, handler=handler, arch_config=read_config(), install_context = TransactionContext.gen_context_from(pkg=pkg, handler=handler, arch_config=self.configman.get_config(),
root_password=root_password) root_password=root_password)
install_context.skip_opt_deps = False install_context.skip_opt_deps = False
install_context.disk_loader = disk_loader install_context.disk_loader = disk_loader
@@ -2612,68 +2612,68 @@ class ArchManager(SoftwareManager):
def requires_root(self, action: SoftwareAction, pkg: ArchPackage) -> bool: def requires_root(self, action: SoftwareAction, pkg: ArchPackage) -> bool:
if action == SoftwareAction.PREPARE: if action == SoftwareAction.PREPARE:
arch_config = read_config() arch_config = self.configman.get_config()
aur_supported = (pkg and pkg.repository == 'aur') or aur.is_supported(arch_config)
if arch_config['refresh_mirrors_startup'] and mirrors.should_sync(self.logger): if RefreshMirrors.should_synchronize(arch_config, aur_supported, self.logger):
return True return True
aur_supported = (pkg and pkg.repository == 'aur') or aur.is_supported(arch_config) return SyncDatabases.should_sync(mirrors_refreshed=False, arch_config=arch_config,
return arch_config['sync_databases_startup'] and database.should_sync(arch_config, aur_supported, None, self.logger) aur_supported=aur_supported, logger=self.logger)
return action != SoftwareAction.SEARCH return action != SoftwareAction.SEARCH
def _start_category_task(self, task_man: TaskManager): def _start_category_task(self, taskman: TaskManager, create_config: CreateConfigFile, downloader: CategoriesDownloader):
task_man.register_task('arch_aur_cats', self.i18n['task.download_categories'], get_icon_path()) taskman.update_progress('arch_aur_cats', 0, self.i18n['task.waiting_task'].format(bold(create_config.task_name)))
task_man.update_progress('arch_aur_cats', 50, None) create_config.join()
arch_config = create_config.config
def _finish_category_task(self, task_man: TaskManager): downloader.expiration = arch_config['categories_exp'] if isinstance(arch_config['categories_exp'], int) else None
task_man.update_progress('arch_aur_cats', 100, None) taskman.update_progress('arch_aur_cats', 50, None)
task_man.finish_task('arch_aur_cats')
def _finish_category_task(self, taskman: TaskManager):
taskman.update_progress('arch_aur_cats', 100, None)
taskman.finish_task('arch_aur_cats')
def prepare(self, task_manager: TaskManager, root_password: str, internet_available: bool): def prepare(self, task_manager: TaskManager, root_password: str, internet_available: bool):
arch_config = read_config(update_file=True) create_config = CreateConfigFile(taskman=task_manager, configman=self.configman, i18n=self.i18n,
task_icon_path=get_icon_path(), logger=self.logger)
create_config.start()
if internet_available and AURIndexUpdater.should_update(arch_config): if internet_available:
self.index_aur = AURIndexUpdater(context=self.context, taskman=task_manager) # must all execute to properly determine the installed packages (even that AUR is disabled) self.index_aur = AURIndexUpdater(context=self.context, taskman=task_manager, create_config=create_config) # must always execute to properly determine the installed packages (even that AUR is disabled)
self.index_aur.start() self.index_aur.start()
aur_supported = aur.is_supported(arch_config) refresh_mirrors = RefreshMirrors(taskman=task_manager, i18n=self.i18n, root_password=root_password,
logger=self.logger, create_config=create_config)
if aur_supported:
ArchCompilationOptimizer(arch_config, self.i18n, self.context.logger, task_manager).start()
if aur_supported or arch_config['repositories']:
self.disk_cache_updater = ArchDiskCacheUpdater(task_man=task_manager,
arch_config=arch_config,
i18n=self.i18n,
logger=self.context.logger,
controller=self,
internet_available=internet_available,
aur_indexer=self.index_aur,
aur_supported=aur_supported)
self.disk_cache_updater.start()
CategoriesDownloader(id_='Arch', http_client=self.context.http_client, logger=self.context.logger,
manager=self, url_categories_file=URL_CATEGORIES_FILE,
categories_path=CATEGORIES_FILE_PATH,
expiration=arch_config['categories_exp'] if isinstance(arch_config['categories_exp'], int) else '',
internet_connection=internet_available,
internet_checker=self.context.internet_checker,
before=lambda: self._start_category_task(task_manager),
after=lambda: self._finish_category_task(task_manager)).start()
refresh_mirrors = None
if internet_available and arch_config['repositories'] and arch_config['refresh_mirrors_startup'] \
and pacman.is_mirrors_available() and mirrors.should_sync(self.logger):
refresh_mirrors = RefreshMirrors(taskman=task_manager, i18n=self.i18n,
root_password=root_password, logger=self.logger,
sort_limit=arch_config['mirrors_sort_limit'])
refresh_mirrors.start() refresh_mirrors.start()
if internet_available and (refresh_mirrors or (arch_config['sync_databases_startup'] and database.should_sync(arch_config, aur_supported, None, self.logger))):
SyncDatabases(taskman=task_manager, root_password=root_password, i18n=self.i18n, SyncDatabases(taskman=task_manager, root_password=root_password, i18n=self.i18n,
logger=self.logger, refresh_mirrors=refresh_mirrors).start() logger=self.logger, refresh_mirrors=refresh_mirrors, create_config=create_config).start()
ArchCompilationOptimizer(i18n=self.i18n, logger=self.context.logger,
taskman=task_manager, create_config=create_config).start()
self.disk_cache_updater = ArchDiskCacheUpdater(taskman=task_manager,
i18n=self.i18n,
logger=self.context.logger,
controller=self,
internet_available=internet_available,
aur_indexer=self.index_aur,
create_config=create_config)
self.disk_cache_updater.start()
task_manager.register_task('arch_aur_cats', self.i18n['task.download_categories'], get_icon_path())
cat_download = CategoriesDownloader(id_='Arch', http_client=self.context.http_client,
logger=self.context.logger,
manager=self, url_categories_file=URL_CATEGORIES_FILE,
categories_path=CATEGORIES_FILE_PATH,
internet_connection=internet_available,
internet_checker=self.context.internet_checker,
after=lambda: self._finish_category_task(task_manager))
cat_download.before = lambda: self._start_category_task(taskman=task_manager, create_config=create_config,
downloader=cat_download)
cat_download.start()
def list_updates(self, internet_available: bool) -> List[PackageUpdate]: def list_updates(self, internet_available: bool) -> List[PackageUpdate]:
installed = self.read_installed(disk_loader=None, internet_available=internet_available).installed installed = self.read_installed(disk_loader=None, internet_available=internet_available).installed
@@ -2763,90 +2763,92 @@ class ArchManager(SoftwareManager):
capitalize_label=capitalize_label) capitalize_label=capitalize_label)
def get_settings(self, screen_width: int, screen_height: int) -> ViewComponent: def get_settings(self, screen_width: int, screen_height: int) -> ViewComponent:
local_config = read_config() arch_config = self.configman.get_config()
max_width = floor(screen_width * 0.25) max_width = floor(screen_width * 0.25)
db_sync_start = self._gen_bool_selector(id_='sync_dbs_start', db_sync_start = self._gen_bool_selector(id_='sync_dbs_start',
label_key='arch.config.sync_dbs', label_key='arch.config.sync_dbs',
tooltip_key='arch.config.sync_dbs_start.tip', tooltip_key='arch.config.sync_dbs_start.tip',
value=bool(local_config['sync_databases_startup']), value=bool(arch_config['sync_databases_startup']),
max_width=max_width) max_width=max_width)
db_sync_start.label += ' ( {} )'.format(self.i18n['initialization'].capitalize()) db_sync_start.label += ' ({})'.format(self.i18n['initialization'].capitalize())
fields = [ fields = [
self._gen_bool_selector(id_='repos', self._gen_bool_selector(id_='repos',
label_key='arch.config.repos', label_key='arch.config.repos',
tooltip_key='arch.config.repos.tip', tooltip_key='arch.config.repos.tip',
value=bool(local_config['repositories']), value=bool(arch_config['repositories']),
max_width=max_width), max_width=max_width),
self._gen_bool_selector(id_='aur', self._gen_bool_selector(id_='aur',
label_key='arch.config.aur', label_key='arch.config.aur',
tooltip_key='arch.config.aur.tip', tooltip_key='arch.config.aur.tip',
value=local_config['aur'], value=arch_config['aur'],
max_width=max_width, max_width=max_width,
capitalize_label=False), capitalize_label=False),
self._gen_bool_selector(id_='opts', self._gen_bool_selector(id_='opts',
label_key='arch.config.optimize', label_key='arch.config.optimize',
tooltip_key='arch.config.optimize.tip', tooltip_key='arch.config.optimize.tip',
value=bool(local_config['optimize']), value=bool(arch_config['optimize']),
label_params=['(AUR)'],
capitalize_label=False,
max_width=max_width), max_width=max_width),
self._gen_bool_selector(id_='autoprovs', self._gen_bool_selector(id_='autoprovs',
label_key='arch.config.automatch_providers', label_key='arch.config.automatch_providers',
tooltip_key='arch.config.automatch_providers.tip', tooltip_key='arch.config.automatch_providers.tip',
value=bool(local_config['automatch_providers']), value=bool(arch_config['automatch_providers']),
max_width=max_width), max_width=max_width),
self._gen_bool_selector(id_='check_dependency_breakage', self._gen_bool_selector(id_='check_dependency_breakage',
label_key='arch.config.check_dependency_breakage', label_key='arch.config.check_dependency_breakage',
tooltip_key='arch.config.check_dependency_breakage.tip', tooltip_key='arch.config.check_dependency_breakage.tip',
value=bool(local_config['check_dependency_breakage']), value=bool(arch_config['check_dependency_breakage']),
max_width=max_width), max_width=max_width),
self._gen_bool_selector(id_='mthread_download', self._gen_bool_selector(id_='mthread_download',
label_key='arch.config.pacman_mthread_download', label_key='arch.config.pacman_mthread_download',
tooltip_key='arch.config.pacman_mthread_download.tip', tooltip_key='arch.config.pacman_mthread_download.tip',
value=local_config['repositories_mthread_download'], value=arch_config['repositories_mthread_download'],
max_width=max_width, max_width=max_width,
capitalize_label=True), capitalize_label=True),
self._gen_bool_selector(id_='sync_dbs', self._gen_bool_selector(id_='sync_dbs',
label_key='arch.config.sync_dbs', label_key='arch.config.sync_dbs',
tooltip_key='arch.config.sync_dbs.tip', tooltip_key='arch.config.sync_dbs.tip',
value=bool(local_config['sync_databases']), value=bool(arch_config['sync_databases']),
max_width=max_width), max_width=max_width),
db_sync_start, db_sync_start,
self._gen_bool_selector(id_='clean_cached', self._gen_bool_selector(id_='clean_cached',
label_key='arch.config.clean_cache', label_key='arch.config.clean_cache',
tooltip_key='arch.config.clean_cache.tip', tooltip_key='arch.config.clean_cache.tip',
value=bool(local_config['clean_cached']), value=bool(arch_config['clean_cached']),
max_width=max_width), max_width=max_width),
self._gen_bool_selector(id_='suggest_unneeded_uninstall', self._gen_bool_selector(id_='suggest_unneeded_uninstall',
label_key='arch.config.suggest_unneeded_uninstall', label_key='arch.config.suggest_unneeded_uninstall',
tooltip_params=['"{}"'.format(self.i18n['arch.config.suggest_optdep_uninstall'])], tooltip_params=['"{}"'.format(self.i18n['arch.config.suggest_optdep_uninstall'])],
tooltip_key='arch.config.suggest_unneeded_uninstall.tip', tooltip_key='arch.config.suggest_unneeded_uninstall.tip',
value=bool(local_config['suggest_unneeded_uninstall']), value=bool(arch_config['suggest_unneeded_uninstall']),
max_width=max_width), max_width=max_width),
self._gen_bool_selector(id_='suggest_optdep_uninstall', self._gen_bool_selector(id_='suggest_optdep_uninstall',
label_key='arch.config.suggest_optdep_uninstall', label_key='arch.config.suggest_optdep_uninstall',
tooltip_key='arch.config.suggest_optdep_uninstall.tip', tooltip_key='arch.config.suggest_optdep_uninstall.tip',
value=bool(local_config['suggest_optdep_uninstall']), value=bool(arch_config['suggest_optdep_uninstall']),
max_width=max_width), max_width=max_width),
self._gen_bool_selector(id_='ref_mirs', self._gen_bool_selector(id_='ref_mirs',
label_key='arch.config.refresh_mirrors', label_key='arch.config.refresh_mirrors',
tooltip_key='arch.config.refresh_mirrors.tip', tooltip_key='arch.config.refresh_mirrors.tip',
value=bool(local_config['refresh_mirrors_startup']), value=bool(arch_config['refresh_mirrors_startup']),
max_width=max_width), max_width=max_width),
TextInputComponent(id_='mirrors_sort_limit', TextInputComponent(id_='mirrors_sort_limit',
label=self.i18n['arch.config.mirrors_sort_limit'], label=self.i18n['arch.config.mirrors_sort_limit'],
tooltip=self.i18n['arch.config.mirrors_sort_limit.tip'], tooltip=self.i18n['arch.config.mirrors_sort_limit.tip'],
only_int=True, only_int=True,
max_width=max_width, max_width=max_width,
value=local_config['mirrors_sort_limit'] if isinstance(local_config['mirrors_sort_limit'], int) else ''), value=arch_config['mirrors_sort_limit'] if isinstance(arch_config['mirrors_sort_limit'], int) else ''),
TextInputComponent(id_='aur_idx_exp', TextInputComponent(id_='aur_idx_exp',
label=self.i18n['arch.config.aur_idx_exp'] + ' (AUR)', label=self.i18n['arch.config.aur_idx_exp'] + ' (AUR)',
tooltip=self.i18n['arch.config.aur_idx_exp.tip'], tooltip=self.i18n['arch.config.aur_idx_exp.tip'],
max_width=max_width, max_width=max_width,
only_int=True, only_int=True,
capitalize_label=False, capitalize_label=False,
value=local_config['aur_idx_exp'] if isinstance(local_config['aur_idx_exp'], int) else ''), value=arch_config['aur_idx_exp'] if isinstance(arch_config['aur_idx_exp'], int) else ''),
new_select(id_='aur_build_only_chosen', new_select(id_='aur_build_only_chosen',
label=self.i18n['arch.config.aur_build_only_chosen'], label=self.i18n['arch.config.aur_build_only_chosen'],
tip=self.i18n['arch.config.aur_build_only_chosen.tip'], tip=self.i18n['arch.config.aur_build_only_chosen.tip'],
@@ -2854,7 +2856,7 @@ class ArchManager(SoftwareManager):
(self.i18n['no'].capitalize(), False, None), (self.i18n['no'].capitalize(), False, None),
(self.i18n['ask'].capitalize(), None, None), (self.i18n['ask'].capitalize(), None, None),
], ],
value=local_config['aur_build_only_chosen'], value=arch_config['aur_build_only_chosen'],
max_width=max_width, max_width=max_width,
type_=SelectViewType.RADIO, type_=SelectViewType.RADIO,
capitalize_label=False), capitalize_label=False),
@@ -2865,21 +2867,21 @@ class ArchManager(SoftwareManager):
(self.i18n['no'].capitalize(), False, None), (self.i18n['no'].capitalize(), False, None),
(self.i18n['ask'].capitalize(), None, None), (self.i18n['ask'].capitalize(), None, None),
], ],
value=local_config['edit_aur_pkgbuild'], value=arch_config['edit_aur_pkgbuild'],
max_width=max_width, max_width=max_width,
type_=SelectViewType.RADIO, type_=SelectViewType.RADIO,
capitalize_label=False), capitalize_label=False),
self._gen_bool_selector(id_='aur_remove_build_dir', self._gen_bool_selector(id_='aur_remove_build_dir',
label_key='arch.config.aur_remove_build_dir', label_key='arch.config.aur_remove_build_dir',
tooltip_key='arch.config.aur_remove_build_dir.tip', tooltip_key='arch.config.aur_remove_build_dir.tip',
value=bool(local_config['aur_remove_build_dir']), value=bool(arch_config['aur_remove_build_dir']),
max_width=max_width, max_width=max_width,
capitalize_label=False), capitalize_label=False),
FileChooserComponent(id_='aur_build_dir', FileChooserComponent(id_='aur_build_dir',
label=self.i18n['arch.config.aur_build_dir'], label=self.i18n['arch.config.aur_build_dir'],
tooltip=self.i18n['arch.config.aur_build_dir.tip'].format(BUILD_DIR), tooltip=self.i18n['arch.config.aur_build_dir.tip'].format(BUILD_DIR),
max_width=max_width, max_width=max_width,
file_path=local_config['aur_build_dir'], file_path=arch_config['aur_build_dir'],
capitalize_label=False, capitalize_label=False,
directory=True), directory=True),
TextInputComponent(id_='arch_cats_exp', TextInputComponent(id_='arch_cats_exp',
@@ -2888,47 +2890,47 @@ class ArchManager(SoftwareManager):
max_width=max_width, max_width=max_width,
only_int=True, only_int=True,
capitalize_label=False, capitalize_label=False,
value=local_config['categories_exp'] if isinstance(local_config['categories_exp'], int) else ''), value=arch_config['categories_exp'] if isinstance(arch_config['categories_exp'], int) else ''),
] ]
return PanelComponent([FormComponent(fields, spaces=False)]) return PanelComponent([FormComponent(fields, spaces=False)])
def save_settings(self, component: PanelComponent) -> Tuple[bool, Optional[List[str]]]: def save_settings(self, component: PanelComponent) -> Tuple[bool, Optional[List[str]]]:
config = read_config() arch_config = self.configman.get_config()
panel = component.components[0] panel = component.components[0]
config['repositories'] = panel.get_component('repos').get_selected() arch_config['repositories'] = panel.get_component('repos').get_selected()
config['aur'] = panel.get_component('aur').get_selected() arch_config['aur'] = panel.get_component('aur').get_selected()
config['optimize'] = panel.get_component('opts').get_selected() arch_config['optimize'] = panel.get_component('opts').get_selected()
config['sync_databases'] = panel.get_component('sync_dbs').get_selected() arch_config['sync_databases'] = panel.get_component('sync_dbs').get_selected()
config['sync_databases_startup'] = panel.get_component('sync_dbs_start').get_selected() arch_config['sync_databases_startup'] = panel.get_component('sync_dbs_start').get_selected()
config['clean_cached'] = panel.get_component('clean_cached').get_selected() arch_config['clean_cached'] = panel.get_component('clean_cached').get_selected()
config['refresh_mirrors_startup'] = panel.get_component('ref_mirs').get_selected() arch_config['refresh_mirrors_startup'] = panel.get_component('ref_mirs').get_selected()
config['mirrors_sort_limit'] = panel.get_component('mirrors_sort_limit').get_int_value() arch_config['mirrors_sort_limit'] = panel.get_component('mirrors_sort_limit').get_int_value()
config['repositories_mthread_download'] = panel.get_component('mthread_download').get_selected() arch_config['repositories_mthread_download'] = panel.get_component('mthread_download').get_selected()
config['automatch_providers'] = panel.get_component('autoprovs').get_selected() arch_config['automatch_providers'] = panel.get_component('autoprovs').get_selected()
config['edit_aur_pkgbuild'] = panel.get_component('edit_aur_pkgbuild').get_selected() arch_config['edit_aur_pkgbuild'] = panel.get_component('edit_aur_pkgbuild').get_selected()
config['aur_remove_build_dir'] = panel.get_component('aur_remove_build_dir').get_selected() arch_config['aur_remove_build_dir'] = panel.get_component('aur_remove_build_dir').get_selected()
config['aur_build_dir'] = panel.get_component('aur_build_dir').file_path arch_config['aur_build_dir'] = panel.get_component('aur_build_dir').file_path
config['aur_build_only_chosen'] = panel.get_component('aur_build_only_chosen').get_selected() arch_config['aur_build_only_chosen'] = panel.get_component('aur_build_only_chosen').get_selected()
config['aur_idx_exp'] = panel.get_component('aur_idx_exp').get_int_value() arch_config['aur_idx_exp'] = panel.get_component('aur_idx_exp').get_int_value()
config['check_dependency_breakage'] = panel.get_component('check_dependency_breakage').get_selected() arch_config['check_dependency_breakage'] = panel.get_component('check_dependency_breakage').get_selected()
config['suggest_optdep_uninstall'] = panel.get_component('suggest_optdep_uninstall').get_selected() arch_config['suggest_optdep_uninstall'] = panel.get_component('suggest_optdep_uninstall').get_selected()
config['suggest_unneeded_uninstall'] = panel.get_component('suggest_unneeded_uninstall').get_selected() arch_config['suggest_unneeded_uninstall'] = panel.get_component('suggest_unneeded_uninstall').get_selected()
config['categories_exp'] = panel.get_component('arch_cats_exp').get_int_value() arch_config['categories_exp'] = panel.get_component('arch_cats_exp').get_int_value()
if not config['aur_build_dir']: if not arch_config['aur_build_dir']:
config['aur_build_dir'] = None arch_config['aur_build_dir'] = None
try: try:
save_config(config, CONFIG_FILE) self.configman.save_config(arch_config)
return True, None return True, None
except: except:
return False, [traceback.format_exc()] return False, [traceback.format_exc()]
def get_upgrade_requirements(self, pkgs: List[ArchPackage], root_password: str, watcher: ProcessWatcher) -> UpgradeRequirements: def get_upgrade_requirements(self, pkgs: List[ArchPackage], root_password: str, watcher: ProcessWatcher) -> UpgradeRequirements:
self.aur_client.clean_caches() self.aur_client.clean_caches()
arch_config = read_config() arch_config = self.configman.get_config()
aur_supported = aur.is_supported(arch_config) aur_supported = aur.is_supported(arch_config)
@@ -2949,7 +2951,7 @@ class ArchManager(SoftwareManager):
def get_custom_actions(self) -> List[CustomSoftwareAction]: def get_custom_actions(self) -> List[CustomSoftwareAction]:
actions = [] actions = []
arch_config = read_config() arch_config = self.configman.get_config()
if pacman.is_mirrors_available(): if pacman.is_mirrors_available():
actions.append(self.custom_actions['ref_mirrors']) actions.append(self.custom_actions['ref_mirrors'])

View File

@@ -497,7 +497,8 @@ def get_current_mirror_countries() -> List[str]:
def is_mirrors_available() -> bool: def is_mirrors_available() -> bool:
return bool(run_cmd('which pacman-mirrors', print_error=False)) code, _ = system.execute(cmd='which pacman-mirrors', output=False)
return code == 0
def map_update_sizes(pkgs: List[str]) -> Dict[str, int]: # bytes: def map_update_sizes(pkgs: List[str]) -> Dict[str, int]: # bytes:

View File

@@ -53,12 +53,12 @@ arch.config.aur_idx_exp=Index expiration
arch.config.aur_idx_exp.tip=It defines the period (in minutes) for the AUR index stored in disc to be considered valid during the initialization process. Use 0 so that it is always updated. arch.config.aur_idx_exp.tip=It defines the period (in minutes) for the AUR index stored in disc to be considered valid during the initialization process. Use 0 so that it is always updated.
arch.config.mirrors_sort_limit=Mirrors sort limit arch.config.mirrors_sort_limit=Mirrors sort limit
arch.config.mirrors_sort_limit.tip=Defines the maximum number of mirrors that will be used for speed sorting. Use 0 for no limit or leave it blank to disable sorting. arch.config.mirrors_sort_limit.tip=Defines the maximum number of mirrors that will be used for speed sorting. Use 0 for no limit or leave it blank to disable sorting.
arch.config.optimize=optimize arch.config.optimize=Optimize {}
arch.config.optimize.tip=La configuració optimitzada s'utilitzarà per fer més ràpida la instal·lació, actualització i reversió dels paquets, en cas contrari s'utilitzarà la configuració del sistema. arch.config.optimize.tip=La configuració optimitzada s'utilitzarà per fer més ràpida la instal·lació, actualització i reversió dels paquets, en cas contrari s'utilitzarà la configuració del sistema.
arch.config.pacman_mthread_download=Multithreaded download (repositories) arch.config.pacman_mthread_download=Multithreaded download (repositories)
arch.config.pacman_mthread_download.tip=Whether the repository packages should be downloaded with a tool that works with threads (it may be faster). pacman-mirrors must be installed. arch.config.pacman_mthread_download.tip=Whether the repository packages should be downloaded with a tool that works with threads (it may be faster). pacman-mirrors must be installed.
arch.config.refresh_mirrors=Refresh mirrors on startup arch.config.refresh_mirrors=Refresh mirrors on startup
arch.config.refresh_mirrors.tip=Refresh the package mirrors once a day on startup ( or after a device reboot ) arch.config.refresh_mirrors.tip=Refresh the package mirrors once a day on startup
arch.config.repos=Repositories packages arch.config.repos=Repositories packages
arch.config.repos.tip=It allows to manage packages from the repositories set arch.config.repos.tip=It allows to manage packages from the repositories set
arch.config.suggest_optdep_uninstall=Uninstall optional dependencies arch.config.suggest_optdep_uninstall=Uninstall optional dependencies
@@ -210,11 +210,15 @@ arch.substatus.pre_hooks=Running pre-transaction hooks
arch.sync.dep_breakage.reason={} requires {} arch.sync.dep_breakage.reason={} requires {}
arch.sync_databases.substatus=Synchronizing package databases arch.sync_databases.substatus=Synchronizing package databases
arch.sync_databases.substatus.error=It was not possible to synchronize the package database arch.sync_databases.substatus.error=It was not possible to synchronize the package database
arch.sync_databases.substatus.synchronized=Synchronized
arch.task.aur.index.status=Generating local AUR index arch.task.aur.index.status=Generating local AUR index
arch.task.aur.index.substatus.checking=Checking for updates
arch.task.aur.index.substatus.download=Downloading the AUR index arch.task.aur.index.substatus.download=Downloading the AUR index
arch.task.aur.index.substatus.error.download=Connection error while downloading the index arch.task.aur.index.substatus.error.download=Connection error while downloading the index
arch.task.aur.index.substatus.error.no_data=Error: empty index arch.task.aur.index.substatus.error.no_data=Error: empty index
arch.task.aur.index.substatus.gen_index=Generating index arch.task.aur.index.substatus.gen_index=Generating index
arch.task.checking_settings=Checking settings
arch.task.disabled=Disabled
arch.task.disk_cache=Indexing packages data arch.task.disk_cache=Indexing packages data
arch.task.disk_cache.checking=Checking index arch.task.disk_cache.checking=Checking index
arch.task.disk_cache.indexed=Indexed arch.task.disk_cache.indexed=Indexed
@@ -222,8 +226,8 @@ arch.task.disk_cache.indexing=Indexing
arch.task.disk_cache.reading_files=Reading files arch.task.disk_cache.reading_files=Reading files
arch.task.disk_cache.waiting_aur_index=Waiting {} arch.task.disk_cache.waiting_aur_index=Waiting {}
arch.task.mirrors=Refreshing mirrors arch.task.mirrors=Refreshing mirrors
arch.task.mirrors.cached=Refreshed
arch.task.optimizing=Optimizing {} arch.task.optimizing=Optimizing {}
arch.task.sync_databases.waiting=Waiting for {}
arch.task.sync_sb.status=Actualitzen {} arch.task.sync_sb.status=Actualitzen {}
arch.uninstall.clean_cached.error=No s'ha pogut eliminar {} versions antigues que es troba al disc arch.uninstall.clean_cached.error=No s'ha pogut eliminar {} versions antigues que es troba al disc
arch.uninstall.clean_cached.substatus=Eliminació de versions antigues del disc arch.uninstall.clean_cached.substatus=Eliminació de versions antigues del disc

View File

@@ -53,12 +53,12 @@ arch.config.aur_idx_exp=Index expiration
arch.config.aur_idx_exp.tip=It defines the period (in minutes) for the AUR index stored in disc to be considered valid during the initialization process. Use 0 so that it is always updated. arch.config.aur_idx_exp.tip=It defines the period (in minutes) for the AUR index stored in disc to be considered valid during the initialization process. Use 0 so that it is always updated.
arch.config.mirrors_sort_limit=Mirrors sort limit arch.config.mirrors_sort_limit=Mirrors sort limit
arch.config.mirrors_sort_limit.tip=Defines the maximum number of mirrors that will be used for speed sorting. Use 0 for no limit or leave it blank to disable sorting. arch.config.mirrors_sort_limit.tip=Defines the maximum number of mirrors that will be used for speed sorting. Use 0 for no limit or leave it blank to disable sorting.
arch.config.optimize=optimize arch.config.optimize=Optimize {}
arch.config.optimize.tip=Optimized settings will be used in order to make the packages installation, upgrading and downgrading faster, otherwise the system settings will be used arch.config.optimize.tip=Optimized settings will be used in order to make the packages installation, upgrading and downgrading faster, otherwise the system settings will be used
arch.config.pacman_mthread_download=Multithreaded download (repositories) arch.config.pacman_mthread_download=Multithreaded download (repositories)
arch.config.pacman_mthread_download.tip=Whether the repository packages should be downloaded with a tool that works with threads (it may be faster). pacman-mirrors must be installed. arch.config.pacman_mthread_download.tip=Whether the repository packages should be downloaded with a tool that works with threads (it may be faster). pacman-mirrors must be installed.
arch.config.refresh_mirrors=Refresh mirrors on startup arch.config.refresh_mirrors=Refresh mirrors on startup
arch.config.refresh_mirrors.tip=Refresh the package mirrors once a day on startup ( or after a device reboot ) arch.config.refresh_mirrors.tip=Refresh the package mirrors once a day on startup
arch.config.repos=Repositories packages arch.config.repos=Repositories packages
arch.config.repos.tip=It allows to manage packages from the repositories set arch.config.repos.tip=It allows to manage packages from the repositories set
arch.config.suggest_optdep_uninstall=Uninstall optional dependencies arch.config.suggest_optdep_uninstall=Uninstall optional dependencies
@@ -210,11 +210,15 @@ arch.substatus.pre_hooks=Running pre-transaction hooks
arch.sync.dep_breakage.reason={} requires {} arch.sync.dep_breakage.reason={} requires {}
arch.sync_databases.substatus=Synchronizing package databases arch.sync_databases.substatus=Synchronizing package databases
arch.sync_databases.substatus.error=It was not possible to synchronize the package database arch.sync_databases.substatus.error=It was not possible to synchronize the package database
arch.sync_databases.substatus.synchronized=Synchronized
arch.task.aur.index.status=Generating local AUR index arch.task.aur.index.status=Generating local AUR index
arch.task.aur.index.substatus.checking=Checking for updates
arch.task.aur.index.substatus.download=Downloading the AUR index arch.task.aur.index.substatus.download=Downloading the AUR index
arch.task.aur.index.substatus.error.download=Connection error while downloading the index arch.task.aur.index.substatus.error.download=Connection error while downloading the index
arch.task.aur.index.substatus.error.no_data=Error: empty index arch.task.aur.index.substatus.error.no_data=Error: empty index
arch.task.aur.index.substatus.gen_index=Generating index arch.task.aur.index.substatus.gen_index=Generating index
arch.task.checking_settings=Checking settings
arch.task.disabled=Disabled
arch.task.disk_cache=Indexing packages data arch.task.disk_cache=Indexing packages data
arch.task.disk_cache.checking=Checking index arch.task.disk_cache.checking=Checking index
arch.task.disk_cache.indexed=Indexed arch.task.disk_cache.indexed=Indexed
@@ -222,8 +226,8 @@ arch.task.disk_cache.indexing=Indexing
arch.task.disk_cache.reading_files=Reading files arch.task.disk_cache.reading_files=Reading files
arch.task.disk_cache.waiting_aur_index=Waiting {} arch.task.disk_cache.waiting_aur_index=Waiting {}
arch.task.mirrors=Refreshing mirrors arch.task.mirrors=Refreshing mirrors
arch.task.mirrors.cached=Refreshed
arch.task.optimizing=Optimizing {} arch.task.optimizing=Optimizing {}
arch.task.sync_databases.waiting=Waiting for {}
arch.task.sync_sb.status=Updating {} arch.task.sync_sb.status=Updating {}
arch.uninstall.clean_cached.error=It was not possible to remove old {} versions found on disk arch.uninstall.clean_cached.error=It was not possible to remove old {} versions found on disk
arch.uninstall.clean_cached.substatus=Removing old versions from disk arch.uninstall.clean_cached.substatus=Removing old versions from disk

View File

@@ -53,12 +53,12 @@ arch.config.aur_idx_exp=Index expiration
arch.config.aur_idx_exp.tip=It defines the period (in minutes) for the AUR index stored in disc to be considered valid during the initialization process. Use 0 so that it is always updated. arch.config.aur_idx_exp.tip=It defines the period (in minutes) for the AUR index stored in disc to be considered valid during the initialization process. Use 0 so that it is always updated.
arch.config.mirrors_sort_limit=Mirrors sort limit arch.config.mirrors_sort_limit=Mirrors sort limit
arch.config.mirrors_sort_limit.tip=Defines the maximum number of mirrors that will be used for speed sorting. Use 0 for no limit or leave it blank to disable sorting. arch.config.mirrors_sort_limit.tip=Defines the maximum number of mirrors that will be used for speed sorting. Use 0 for no limit or leave it blank to disable sorting.
arch.config.optimize=optimize arch.config.optimize=Optimize {}
arch.config.optimize.tip=Optimized settings will be used in order to make the packages installation, upgrading and downgrading faster, otherwise the system settings will be used arch.config.optimize.tip=Optimized settings will be used in order to make the packages installation, upgrading and downgrading faster, otherwise the system settings will be used
arch.config.pacman_mthread_download=Multi-threaded download (repositories) arch.config.pacman_mthread_download=Multi-threaded download (repositories)
arch.config.pacman_mthread_download.tip=Whether the repository packages should be downloaded with a tool that works with threads (it may be faster). pacman-mirrors must be installed. arch.config.pacman_mthread_download.tip=Whether the repository packages should be downloaded with a tool that works with threads (it may be faster). pacman-mirrors must be installed.
arch.config.refresh_mirrors=Refresh mirrors on startup arch.config.refresh_mirrors=Refresh mirrors on startup
arch.config.refresh_mirrors.tip=Refresh the package mirrors once a day on startup ( or after a device reboot ) arch.config.refresh_mirrors.tip=Refresh the package mirrors once a day on startup
arch.config.repos=Repositories packages arch.config.repos=Repositories packages
arch.config.repos.tip=It allows to manage packages from the repositories set arch.config.repos.tip=It allows to manage packages from the repositories set
arch.config.suggest_optdep_uninstall=Uninstall optional dependencies arch.config.suggest_optdep_uninstall=Uninstall optional dependencies
@@ -210,11 +210,15 @@ arch.substatus.pre_hooks=Running pre-transaction hooks
arch.sync.dep_breakage.reason={} requires {} arch.sync.dep_breakage.reason={} requires {}
arch.sync_databases.substatus=Synchronizing package databases arch.sync_databases.substatus=Synchronizing package databases
arch.sync_databases.substatus.error=It was not possible to synchronize the package database arch.sync_databases.substatus.error=It was not possible to synchronize the package database
arch.sync_databases.substatus.synchronized=Synchronized
arch.task.aur.index.status=Generating local AUR index arch.task.aur.index.status=Generating local AUR index
arch.task.aur.index.substatus.checking=Checking for updates
arch.task.aur.index.substatus.download=Downloading the AUR index arch.task.aur.index.substatus.download=Downloading the AUR index
arch.task.aur.index.substatus.error.download=Connection error while downloading the index arch.task.aur.index.substatus.error.download=Connection error while downloading the index
arch.task.aur.index.substatus.error.no_data=Error: empty index arch.task.aur.index.substatus.error.no_data=Error: empty index
arch.task.aur.index.substatus.gen_index=Generating index arch.task.aur.index.substatus.gen_index=Generating index
arch.task.checking_settings=Checking settings
arch.task.disabled=Disabled
arch.task.disk_cache=Indexing packages data arch.task.disk_cache=Indexing packages data
arch.task.disk_cache.checking=Checking index arch.task.disk_cache.checking=Checking index
arch.task.disk_cache.indexed=Indexed arch.task.disk_cache.indexed=Indexed
@@ -222,8 +226,8 @@ arch.task.disk_cache.indexing=Indexing
arch.task.disk_cache.reading_files=Reading files arch.task.disk_cache.reading_files=Reading files
arch.task.disk_cache.waiting_aur_index=Waiting {} arch.task.disk_cache.waiting_aur_index=Waiting {}
arch.task.mirrors=Refreshing mirrors arch.task.mirrors=Refreshing mirrors
arch.task.mirrors.cached=Refreshed
arch.task.optimizing=Optimizing {} arch.task.optimizing=Optimizing {}
arch.task.sync_databases.waiting=Waiting for {}
arch.task.sync_sb.status=Updating {} arch.task.sync_sb.status=Updating {}
arch.uninstall.clean_cached.error=It was not possible to remove old {} versions found on disk arch.uninstall.clean_cached.error=It was not possible to remove old {} versions found on disk
arch.uninstall.clean_cached.substatus=Removing old versions from disk arch.uninstall.clean_cached.substatus=Removing old versions from disk

View File

@@ -53,12 +53,12 @@ arch.config.aur_idx_exp=Expiración del índice
arch.config.aur_idx_exp.tip=Define el período (en minutos) para que el índice AUR almacenado en el disco se considere válido durante el proceso de inicialización. Utilice 0 para que esté siempre actualizado. arch.config.aur_idx_exp.tip=Define el período (en minutos) para que el índice AUR almacenado en el disco se considere válido durante el proceso de inicialización. Utilice 0 para que esté siempre actualizado.
arch.config.mirrors_sort_limit=Límite de ordenación de espejos arch.config.mirrors_sort_limit=Límite de ordenación de espejos
arch.config.mirrors_sort_limit.tip=Define el número máximo de espejos que se utilizarán para la ordenación por velocidad. Use 0 para no limitar o déjelo en blanco para deshabilitar la clasificación. arch.config.mirrors_sort_limit.tip=Define el número máximo de espejos que se utilizarán para la ordenación por velocidad. Use 0 para no limitar o déjelo en blanco para deshabilitar la clasificación.
arch.config.optimize=optimizar arch.config.optimize=Optimizar {}
arch.config.optimize.tip=Se usará la configuración optimizada para que la instalación, actualización y reversión de los paquetes sean más rápidas, de lo contrario se usará la configuración del sistema arch.config.optimize.tip=Se usará la configuración optimizada para que la instalación, actualización y reversión de los paquetes sean más rápidas, de lo contrario se usará la configuración del sistema
arch.config.pacman_mthread_download=Descarga segmentada (repositorios) arch.config.pacman_mthread_download=Descarga segmentada (repositorios)
arch.config.pacman_mthread_download.tip=Si los paquetes de los repositorios deben descargarse con una herramienta que usa segmentación/threads (puede ser más rápido). pacman-mirrors necesita estar instalado. arch.config.pacman_mthread_download.tip=Si los paquetes de los repositorios deben descargarse con una herramienta que usa segmentación/threads (puede ser más rápido). pacman-mirrors necesita estar instalado.
arch.config.refresh_mirrors=Actualizar espejos al iniciar arch.config.refresh_mirrors=Actualizar espejos al iniciar
arch.config.refresh_mirrors.tip=Actualiza los espejos de paquetes una vez al día al iniciar ( o después de reiniciar el dispositivo ) arch.config.refresh_mirrors.tip=Actualiza los espejos de paquetes una vez al día al iniciar
arch.config.repos=Paquetes de repositorios arch.config.repos=Paquetes de repositorios
arch.config.repos.tip=Permite gestionar paquetes de los repositorios configurados arch.config.repos.tip=Permite gestionar paquetes de los repositorios configurados
arch.config.suggest_optdep_uninstall=Desinstalar dependencias opcionales arch.config.suggest_optdep_uninstall=Desinstalar dependencias opcionales
@@ -210,11 +210,15 @@ arch.substatus.pre_hooks=Ejecutando ganchos pre-transacción
arch.sync.dep_breakage.reason={} necesita de {} arch.sync.dep_breakage.reason={} necesita de {}
arch.sync_databases.substatus=Sincronizando bases de paquetes arch.sync_databases.substatus=Sincronizando bases de paquetes
arch.sync_databases.substatus.error=No fue posible sincronizar la base de paquetes arch.sync_databases.substatus.error=No fue posible sincronizar la base de paquetes
arch.sync_databases.substatus.synchronized=Sincronizado
arch.task.aur.index.status=Generando índice local del AUR arch.task.aur.index.status=Generando índice local del AUR
arch.task.aur.index.substatus.checking=Buscando actualizaciones
arch.task.aur.index.substatus.download=Descargando el índice arch.task.aur.index.substatus.download=Descargando el índice
arch.task.aur.index.substatus.error.download=Error de conexión al descargar el índice arch.task.aur.index.substatus.error.download=Error de conexión al descargar el índice
arch.task.aur.index.substatus.error.no_data=Error: índice vacío arch.task.aur.index.substatus.error.no_data=Error: índice vacío
arch.task.aur.index.substatus.gen_index=Generando índice arch.task.aur.index.substatus.gen_index=Generando índice
arch.task.checking_settings=Verificando configuraciones
arch.task.disabled=Deshabilitado
arch.task.disk_cache=Indexando datos de paquetes arch.task.disk_cache=Indexando datos de paquetes
arch.task.disk_cache.checking=Comprobando índice arch.task.disk_cache.checking=Comprobando índice
arch.task.disk_cache.indexed=Indexados arch.task.disk_cache.indexed=Indexados
@@ -222,8 +226,8 @@ arch.task.disk_cache.indexing=Indexando
arch.task.disk_cache.reading_files=Lendo archivos arch.task.disk_cache.reading_files=Lendo archivos
arch.task.disk_cache.waiting_aur_index=Esperando {} arch.task.disk_cache.waiting_aur_index=Esperando {}
arch.task.mirrors=Actualizando espejos arch.task.mirrors=Actualizando espejos
arch.task.mirrors.cached=Actualizados
arch.task.optimizing=Optimizando {} arch.task.optimizing=Optimizando {}
arch.task.sync_databases.waiting=Esperando por {}
arch.task.sync_sb.status=Actualizando {} arch.task.sync_sb.status=Actualizando {}
arch.uninstall.clean_cached.error=No fue posible eliminar versiones antiguas de {} encontradas en disco arch.uninstall.clean_cached.error=No fue posible eliminar versiones antiguas de {} encontradas en disco
arch.uninstall.clean_cached.substatus=Eliminando versiones antiguas del disco arch.uninstall.clean_cached.substatus=Eliminando versiones antiguas del disco

View File

@@ -53,12 +53,12 @@ arch.config.aur_idx_exp=Index expiration
arch.config.aur_idx_exp.tip=It defines the period (in minutes) for the AUR index stored in disc to be considered valid during the initialization process. Use 0 so that it is always updated. arch.config.aur_idx_exp.tip=It defines the period (in minutes) for the AUR index stored in disc to be considered valid during the initialization process. Use 0 so that it is always updated.
arch.config.mirrors_sort_limit=Limite de tri des miroirs arch.config.mirrors_sort_limit=Limite de tri des miroirs
arch.config.mirrors_sort_limit.tip=Définit le nombre maximal de miroirs utilisés pour trier vite. 0 pour aucune limite ou vide pour désactiver le tri. arch.config.mirrors_sort_limit.tip=Définit le nombre maximal de miroirs utilisés pour trier vite. 0 pour aucune limite ou vide pour désactiver le tri.
arch.config.optimize=optimizer arch.config.optimize=Optimizer {}
arch.config.optimize.tip=Utiliser des paramètres optimisés pour rendre l'installation, mise à jour et downgrade des paquets plus rapide. À défaut, les paramètres systèmes seront utilisés. arch.config.optimize.tip=Utiliser des paramètres optimisés pour rendre l'installation, mise à jour et downgrade des paquets plus rapide. À défaut, les paramètres systèmes seront utilisés.
arch.config.pacman_mthread_download=Téléchargement parallèle (repos) arch.config.pacman_mthread_download=Téléchargement parallèle (repos)
arch.config.pacman_mthread_download.tip=Si il faut utiliser un outil qui télécharge les paquets du répos en parallèle (plus rapide). pacman-mirrors doit être installé. arch.config.pacman_mthread_download.tip=Si il faut utiliser un outil qui télécharge les paquets du répos en parallèle (plus rapide). pacman-mirrors doit être installé.
arch.config.refresh_mirrors=Actualiser les miroirs au démarrage arch.config.refresh_mirrors=Actualiser les miroirs au démarrage
arch.config.refresh_mirrors.tip=Actualiser les miroirs du paquet une fois par jour au démarrage ( ou après redémarrage système ) arch.config.refresh_mirrors.tip=Actualiser les miroirs du paquet une fois par jour au démarrage
arch.config.repos=Repos des paquets arch.config.repos=Repos des paquets
arch.config.repos.tip=Permet de gerer les paquets du repo arch.config.repos.tip=Permet de gerer les paquets du repo
arch.config.suggest_optdep_uninstall=Désinstaller les dépendances optionnelles arch.config.suggest_optdep_uninstall=Désinstaller les dépendances optionnelles
@@ -210,11 +210,15 @@ arch.substatus.pre_hooks=Éxécution des pre-transaction hooks
arch.sync.dep_breakage.reason={} requiert {} arch.sync.dep_breakage.reason={} requiert {}
arch.sync_databases.substatus=Synchronisation des bases de données du paquet arch.sync_databases.substatus=Synchronisation des bases de données du paquet
arch.sync_databases.substatus.error=Impossible de synchroniser les bases de données du paquet arch.sync_databases.substatus.error=Impossible de synchroniser les bases de données du paquet
arch.sync_databases.substatus.synchronized=Synchronized
arch.task.aur.index.status=Generating local AUR index arch.task.aur.index.status=Generating local AUR index
arch.task.aur.index.substatus.checking=Checking for updates
arch.task.aur.index.substatus.download=Downloading the AUR index arch.task.aur.index.substatus.download=Downloading the AUR index
arch.task.aur.index.substatus.error.download=Connection error while downloading the index arch.task.aur.index.substatus.error.download=Connection error while downloading the index
arch.task.aur.index.substatus.error.no_data=Error: empty index arch.task.aur.index.substatus.error.no_data=Error: empty index
arch.task.aur.index.substatus.gen_index=Generating index arch.task.aur.index.substatus.gen_index=Generating index
arch.task.checking_settings=Checking settings
arch.task.disabled=Disabled
arch.task.disk_cache=Indexation des données des paquets arch.task.disk_cache=Indexation des données des paquets
arch.task.disk_cache.checking=Verification de l'index arch.task.disk_cache.checking=Verification de l'index
arch.task.disk_cache.indexed=Indexé arch.task.disk_cache.indexed=Indexé
@@ -222,8 +226,8 @@ arch.task.disk_cache.indexing=Indexation
arch.task.disk_cache.reading_files=Lecture des fichiers arch.task.disk_cache.reading_files=Lecture des fichiers
arch.task.disk_cache.waiting_aur_index=Waiting {} arch.task.disk_cache.waiting_aur_index=Waiting {}
arch.task.mirrors=Mise à jour des miroirs arch.task.mirrors=Mise à jour des miroirs
arch.task.mirrors.cached=Refreshed
arch.task.optimizing=Optimisation {} arch.task.optimizing=Optimisation {}
arch.task.sync_databases.waiting=Attente de {}
arch.task.sync_sb.status=Mise à jour {} arch.task.sync_sb.status=Mise à jour {}
arch.uninstall.clean_cached.error=Impossible de supprimer les anciennes version de {} trouvées sur le disque arch.uninstall.clean_cached.error=Impossible de supprimer les anciennes version de {} trouvées sur le disque
arch.uninstall.clean_cached.substatus=Suppression des anciennes versions arch.uninstall.clean_cached.substatus=Suppression des anciennes versions

View File

@@ -53,12 +53,12 @@ arch.config.aur_idx_exp=Index expiration
arch.config.aur_idx_exp.tip=It defines the period (in minutes) for the AUR index stored in disc to be considered valid during the initialization process. Use 0 so that it is always updated. arch.config.aur_idx_exp.tip=It defines the period (in minutes) for the AUR index stored in disc to be considered valid during the initialization process. Use 0 so that it is always updated.
arch.config.mirrors_sort_limit=Mirrors sort limit arch.config.mirrors_sort_limit=Mirrors sort limit
arch.config.mirrors_sort_limit.tip=Defines the maximum number of mirrors that will be used for speed sorting. Use 0 for no limit or leave it blank to disable sorting. arch.config.mirrors_sort_limit.tip=Defines the maximum number of mirrors that will be used for speed sorting. Use 0 for no limit or leave it blank to disable sorting.
arch.config.optimize=optimize arch.config.optimize=Optimize {}
arch.config.optimize.tip=Verranno utilizzate le impostazioni ottimizzate per velocizzare l'installazione, l'aggiornamento e l'inversione dei pacchetti, altrimenti verranno utilizzate le impostazioni di sistema arch.config.optimize.tip=Verranno utilizzate le impostazioni ottimizzate per velocizzare l'installazione, l'aggiornamento e l'inversione dei pacchetti, altrimenti verranno utilizzate le impostazioni di sistema
arch.config.pacman_mthread_download=Multithreaded download (repositories) arch.config.pacman_mthread_download=Multithreaded download (repositories)
arch.config.pacman_mthread_download.tip=Whether the repository packages should be downloaded with a tool that works with threads (it may be faster). pacman-mirrors must be installed. arch.config.pacman_mthread_download.tip=Whether the repository packages should be downloaded with a tool that works with threads (it may be faster). pacman-mirrors must be installed.
arch.config.refresh_mirrors=Refresh mirrors on startup arch.config.refresh_mirrors=Refresh mirrors on startup
arch.config.refresh_mirrors.tip=Refresh the package mirrors once a day on startup ( or after a device reboot ) arch.config.refresh_mirrors.tip=Refresh the package mirrors once a day on startup
arch.config.repos=Repositories packages arch.config.repos=Repositories packages
arch.config.repos.tip=It allows to manage packages from the repositories set arch.config.repos.tip=It allows to manage packages from the repositories set
arch.config.suggest_optdep_uninstall=Uninstall optional dependencies arch.config.suggest_optdep_uninstall=Uninstall optional dependencies
@@ -210,11 +210,15 @@ arch.substatus.pre_hooks=Running pre-transaction hooks
arch.sync.dep_breakage.reason={} requires {} arch.sync.dep_breakage.reason={} requires {}
arch.sync_databases.substatus=Synchronizing package databases arch.sync_databases.substatus=Synchronizing package databases
arch.sync_databases.substatus.error=It was not possible to synchronize the package database arch.sync_databases.substatus.error=It was not possible to synchronize the package database
arch.sync_databases.substatus.synchronized=Synchronized
arch.task.aur.index.status=Generating local AUR index arch.task.aur.index.status=Generating local AUR index
arch.task.aur.index.substatus.checking=Checking for updates
arch.task.aur.index.substatus.download=Downloading the AUR index arch.task.aur.index.substatus.download=Downloading the AUR index
arch.task.aur.index.substatus.error.download=Connection error while downloading the index arch.task.aur.index.substatus.error.download=Connection error while downloading the index
arch.task.aur.index.substatus.error.no_data=Error: empty index arch.task.aur.index.substatus.error.no_data=Error: empty index
arch.task.aur.index.substatus.gen_index=Generating index arch.task.aur.index.substatus.gen_index=Generating index
arch.task.checking_settings=Checking settings
arch.task.disabled=Disabled
arch.task.disk_cache=Indexing packages data arch.task.disk_cache=Indexing packages data
arch.task.disk_cache.checking=Checking index arch.task.disk_cache.checking=Checking index
arch.task.disk_cache.indexed=Indexed arch.task.disk_cache.indexed=Indexed
@@ -222,8 +226,8 @@ arch.task.disk_cache.indexing=Indexing
arch.task.disk_cache.reading_files=Reading files arch.task.disk_cache.reading_files=Reading files
arch.task.disk_cache.waiting_aur_index=Waiting {} arch.task.disk_cache.waiting_aur_index=Waiting {}
arch.task.mirrors=Aggiornando i mirror arch.task.mirrors=Aggiornando i mirror
arch.task.mirrors.cached=Refreshed
arch.task.optimizing=Ottimizzando {} arch.task.optimizing=Ottimizzando {}
arch.task.sync_databases.waiting=Waiting for {}
arch.task.sync_sb.status=Aggiornando {} arch.task.sync_sb.status=Aggiornando {}
arch.uninstall.clean_cached.error=Non è stato possibile rimuovere le vecchie {} versioni trovate sul disco arch.uninstall.clean_cached.error=Non è stato possibile rimuovere le vecchie {} versioni trovate sul disco
arch.uninstall.clean_cached.substatus=Rimozione di versioni precedenti dal disco arch.uninstall.clean_cached.substatus=Rimozione di versioni precedenti dal disco

View File

@@ -53,7 +53,7 @@ arch.config.aur_idx_exp=Expiração do índice
arch.config.aur_idx_exp.tip=Define o período (em minutos) em que o índice do AUR armazenado em disco é considerado válido durante a inicialização. Utilize 0 para que ele sempre seja atualizado. arch.config.aur_idx_exp.tip=Define o período (em minutos) em que o índice do AUR armazenado em disco é considerado válido durante a inicialização. Utilize 0 para que ele sempre seja atualizado.
arch.config.mirrors_sort_limit=Limite de ordenação de espelhos arch.config.mirrors_sort_limit=Limite de ordenação de espelhos
arch.config.mirrors_sort_limit.tip=Define o número máximo de espelhos que serão utilizados para a ordenação por velocidade. Utilize 0 para não limitar ou deixe em branco para desabilitar a ordenação. arch.config.mirrors_sort_limit.tip=Define o número máximo de espelhos que serão utilizados para a ordenação por velocidade. Utilize 0 para não limitar ou deixe em branco para desabilitar a ordenação.
arch.config.optimize=Otimizar arch.config.optimize=Otimizar {}
arch.config.pacman_mthread_download=Download segmentado (repositórios) arch.config.pacman_mthread_download=Download segmentado (repositórios)
arch.config.pacman_mthread_download.tip=Se os pacotes dos repositórios devem baixados através de uma ferramenta que trabalha com segmentação/threads (pode ser mais rápido). pacman-mirrors precisa estar instalado. arch.config.pacman_mthread_download.tip=Se os pacotes dos repositórios devem baixados através de uma ferramenta que trabalha com segmentação/threads (pode ser mais rápido). pacman-mirrors precisa estar instalado.
arch.config.refresh_mirrors=Atualizar espelhos ao iniciar arch.config.refresh_mirrors=Atualizar espelhos ao iniciar
@@ -209,11 +209,15 @@ arch.substatus.pre_hooks=Executando ganchos pré-transação
arch.sync.dep_breakage.reason={} precisa de {} arch.sync.dep_breakage.reason={} precisa de {}
arch.sync_databases.substatus=Sincronizando bases de pacotes arch.sync_databases.substatus=Sincronizando bases de pacotes
arch.sync_databases.substatus.error=Não foi possível sincronizar as bases de pacotes arch.sync_databases.substatus.error=Não foi possível sincronizar as bases de pacotes
arch.sync_databases.substatus.synchronized=Sincronizado
arch.task.aur.index.status=Gerando índice local do AUR arch.task.aur.index.status=Gerando índice local do AUR
arch.task.aur.index.substatus.checking=Checando atualizações
arch.task.aur.index.substatus.download=Baixando o índice arch.task.aur.index.substatus.download=Baixando o índice
arch.task.aur.index.substatus.error.download=Erro de conexão ao baixar o índice arch.task.aur.index.substatus.error.download=Erro de conexão ao baixar o índice
arch.task.aur.index.substatus.error.no_data=Error: índice vazio arch.task.aur.index.substatus.error.no_data=Error: índice vazio
arch.task.aur.index.substatus.gen_index=Gerando índice arch.task.aur.index.substatus.gen_index=Gerando índice
arch.task.checking_settings=Verificando configurações
arch.task.disabled=Desabilitado
arch.task.disk_cache=Indexando dados de pacotes arch.task.disk_cache=Indexando dados de pacotes
arch.task.disk_cache.checking=Verificando índice arch.task.disk_cache.checking=Verificando índice
arch.task.disk_cache.indexed=Indexados arch.task.disk_cache.indexed=Indexados
@@ -221,8 +225,8 @@ arch.task.disk_cache.indexing=Indexando
arch.task.disk_cache.reading_files=Lendo arquivos arch.task.disk_cache.reading_files=Lendo arquivos
arch.task.disk_cache.waiting_aur_index=Aguardando {} arch.task.disk_cache.waiting_aur_index=Aguardando {}
arch.task.mirrors=Atualizando espelhos arch.task.mirrors=Atualizando espelhos
arch.task.mirrors.cached=Atualizados
arch.task.optimizing=Otimizando {} arch.task.optimizing=Otimizando {}
arch.task.sync_databases.waiting=Aguardando por {}
arch.task.sync_sb.status=Atualizando {} arch.task.sync_sb.status=Atualizando {}
arch.uninstall.clean_cached.error=Não foi possível remover versões antigas de {} encontradas em disco arch.uninstall.clean_cached.error=Não foi possível remover versões antigas de {} encontradas em disco
arch.uninstall.clean_cached.substatus=Removendo versões antigas do disco arch.uninstall.clean_cached.substatus=Removendo versões antigas do disco

View File

@@ -53,12 +53,12 @@ arch.config.aur_idx_exp=Index expiration
arch.config.aur_idx_exp.tip=It defines the period (in minutes) for the AUR index stored in disc to be considered valid during the initialization process. Use 0 so that it is always updated. arch.config.aur_idx_exp.tip=It defines the period (in minutes) for the AUR index stored in disc to be considered valid during the initialization process. Use 0 so that it is always updated.
arch.config.mirrors_sort_limit=Ограничение сортировки зеркал arch.config.mirrors_sort_limit=Ограничение сортировки зеркал
arch.config.mirrors_sort_limit.tip=Определяет максимальное количество зеркал, которые будут использоваться для сортировки по скорости. Используйте 0 для No limit или оставьте его пустым, чтобы отключить сортировку. arch.config.mirrors_sort_limit.tip=Определяет максимальное количество зеркал, которые будут использоваться для сортировки по скорости. Используйте 0 для No limit или оставьте его пустым, чтобы отключить сортировку.
arch.config.optimize=Оптимизация arch.config.optimize=Оптимизация {}
arch.config.optimize.tip=Оптимизированные настройки будут использоваться для ускорения установки пакетов, в противном случае будут использоваться системные настройки arch.config.optimize.tip=Оптимизированные настройки будут использоваться для ускорения установки пакетов, в противном случае будут использоваться системные настройки
arch.config.pacman_mthread_download=Multithreaded download (repositories) arch.config.pacman_mthread_download=Multithreaded download (repositories)
arch.config.pacman_mthread_download.tip=Whether the repository packages should be downloaded with a tool that works with threads (it may be faster). pacman-mirrors must be installed. arch.config.pacman_mthread_download.tip=Whether the repository packages should be downloaded with a tool that works with threads (it may be faster). pacman-mirrors must be installed.
arch.config.refresh_mirrors=Обновить зеркала при запуске arch.config.refresh_mirrors=Обновить зеркала при запуске
arch.config.refresh_mirrors.tip=Обновляйте зеркала пакета один раз в день при запуске (или после перезагрузки устройства) arch.config.refresh_mirrors.tip=Обновляйте зеркала пакета один раз в день при запуске
arch.config.repos=Пакеты репозиториев arch.config.repos=Пакеты репозиториев
arch.config.repos.tip=Он позволяет управлять пакетами из набора репозиториев arch.config.repos.tip=Он позволяет управлять пакетами из набора репозиториев
arch.config.suggest_optdep_uninstall=Uninstall optional dependencies arch.config.suggest_optdep_uninstall=Uninstall optional dependencies
@@ -210,11 +210,15 @@ arch.substatus.pre_hooks=Running pre-transaction hooks
arch.sync.dep_breakage.reason={} requires {} arch.sync.dep_breakage.reason={} requires {}
arch.sync_databases.substatus=Синхронизация баз данных пакетов arch.sync_databases.substatus=Синхронизация баз данных пакетов
arch.sync_databases.substatus.error=Синхронизировать базу данных пакета не удалось arch.sync_databases.substatus.error=Синхронизировать базу данных пакета не удалось
arch.sync_databases.substatus.synchronized=Synchronized
arch.task.aur.index.status=Generating local AUR index arch.task.aur.index.status=Generating local AUR index
arch.task.aur.index.substatus.checking=Checking for updates
arch.task.aur.index.substatus.download=Downloading the AUR index arch.task.aur.index.substatus.download=Downloading the AUR index
arch.task.aur.index.substatus.error.download=Connection error while downloading the index arch.task.aur.index.substatus.error.download=Connection error while downloading the index
arch.task.aur.index.substatus.error.no_data=Error: empty index arch.task.aur.index.substatus.error.no_data=Error: empty index
arch.task.aur.index.substatus.gen_index=Generating index arch.task.aur.index.substatus.gen_index=Generating index
arch.task.checking_settings=Checking settings
arch.task.disabled=Disabled
arch.task.disk_cache=Indexing packages data arch.task.disk_cache=Indexing packages data
arch.task.disk_cache.checking=Checking index arch.task.disk_cache.checking=Checking index
arch.task.disk_cache.indexed=Indexed arch.task.disk_cache.indexed=Indexed
@@ -222,8 +226,8 @@ arch.task.disk_cache.indexing=Indexing
arch.task.disk_cache.reading_files=Reading files arch.task.disk_cache.reading_files=Reading files
arch.task.disk_cache.waiting_aur_index=Waiting {} arch.task.disk_cache.waiting_aur_index=Waiting {}
arch.task.mirrors=Обновление зеркал arch.task.mirrors=Обновление зеркал
arch.task.mirrors.cached=Refreshed
arch.task.optimizing=Optimizing {} arch.task.optimizing=Optimizing {}
arch.task.sync_databases.waiting=Waiting for {}
arch.task.sync_sb.status=Updating {} arch.task.sync_sb.status=Updating {}
arch.uninstall.clean_cached.error=It was not possible to remove old {} versions found on disk arch.uninstall.clean_cached.error=It was not possible to remove old {} versions found on disk
arch.uninstall.clean_cached.substatus=Removing old versions from disk arch.uninstall.clean_cached.substatus=Removing old versions from disk

View File

@@ -53,12 +53,12 @@ arch.config.aur_idx_exp=Index expiration
arch.config.aur_idx_exp.tip=It defines the period (in minutes) for the AUR index stored in disc to be considered valid during the initialization process. Use 0 so that it is always updated. arch.config.aur_idx_exp.tip=It defines the period (in minutes) for the AUR index stored in disc to be considered valid during the initialization process. Use 0 so that it is always updated.
arch.config.mirrors_sort_limit=Yansı sıralama sınırı arch.config.mirrors_sort_limit=Yansı sıralama sınırı
arch.config.mirrors_sort_limit.tip=Hız sıralama için kullanılacak maksimum yansı sayısını tanımlar. Sınırsız olması için 0 kullanın veya sıralamayı devre dışı bırakmak için boş bırakın. arch.config.mirrors_sort_limit.tip=Hız sıralama için kullanılacak maksimum yansı sayısını tanımlar. Sınırsız olması için 0 kullanın veya sıralamayı devre dışı bırakmak için boş bırakın.
arch.config.optimize=optimize arch.config.optimize=Optimize {}
arch.config.optimize.tip=Paketlerin kurulumunu, yükseltilmesini ve indirilmesini hızlandırmak için optimize edilmiş ayarlar kullanılacak, aksi takdirde sistem ayarları kullanılacak arch.config.optimize.tip=Paketlerin kurulumunu, yükseltilmesini ve indirilmesini hızlandırmak için optimize edilmiş ayarlar kullanılacak, aksi takdirde sistem ayarları kullanılacak
arch.config.pacman_mthread_download=Multithreaded download (repositories) arch.config.pacman_mthread_download=Multithreaded download (repositories)
arch.config.pacman_mthread_download.tip=Whether the repository packages should be downloaded with a tool that works with threads (it may be faster). pacman-mirrors must be installed. arch.config.pacman_mthread_download.tip=Whether the repository packages should be downloaded with a tool that works with threads (it may be faster). pacman-mirrors must be installed.
arch.config.refresh_mirrors=Başlangıçta yansıları yenile arch.config.refresh_mirrors=Başlangıçta yansıları yenile
arch.config.refresh_mirrors.tip=Paket yansılarını başlangıçta günde bir kez (veya cihaz yeniden başlatıldıktan sonra) yenileyin arch.config.refresh_mirrors.tip=Paket yansılarını başlangıçta günde bir kez yenileyin
arch.config.repos=Depo paketleri arch.config.repos=Depo paketleri
arch.config.repos.tip=Paketleri depolardan yönetmeye izin verir arch.config.repos.tip=Paketleri depolardan yönetmeye izin verir
arch.config.suggest_optdep_uninstall=Uninstall optional dependencies arch.config.suggest_optdep_uninstall=Uninstall optional dependencies
@@ -210,11 +210,15 @@ arch.substatus.pre_hooks=Running pre-transaction hooks
arch.sync.dep_breakage.reason={} requires {} arch.sync.dep_breakage.reason={} requires {}
arch.sync_databases.substatus=Paket veritabanı eşitleniyor arch.sync_databases.substatus=Paket veritabanı eşitleniyor
arch.sync_databases.substatus.error=Paket veritabanı eşitlenemedi arch.sync_databases.substatus.error=Paket veritabanı eşitlenemedi
arch.sync_databases.substatus.synchronized=Synchronized
arch.task.aur.index.status=Generating local AUR index arch.task.aur.index.status=Generating local AUR index
arch.task.aur.index.substatus.checking=Checking for updates
arch.task.aur.index.substatus.download=Downloading the AUR index arch.task.aur.index.substatus.download=Downloading the AUR index
arch.task.aur.index.substatus.error.download=Connection error while downloading the index arch.task.aur.index.substatus.error.download=Connection error while downloading the index
arch.task.aur.index.substatus.error.no_data=Error: empty index arch.task.aur.index.substatus.error.no_data=Error: empty index
arch.task.aur.index.substatus.gen_index=Generating index arch.task.aur.index.substatus.gen_index=Generating index
arch.task.checking_settings=Checking settings
arch.task.disabled=Disabled
arch.task.disk_cache=Indexing packages data arch.task.disk_cache=Indexing packages data
arch.task.disk_cache.checking=Checking index arch.task.disk_cache.checking=Checking index
arch.task.disk_cache.indexed=Indexed arch.task.disk_cache.indexed=Indexed
@@ -222,8 +226,8 @@ arch.task.disk_cache.indexing=Indexing
arch.task.disk_cache.reading_files=Reading files arch.task.disk_cache.reading_files=Reading files
arch.task.disk_cache.waiting_aur_index=Waiting {} arch.task.disk_cache.waiting_aur_index=Waiting {}
arch.task.mirrors=Yansılar yenileniyor arch.task.mirrors=Yansılar yenileniyor
arch.task.mirrors.cached=Refreshed
arch.task.optimizing=Uygun hale getiriliyor {} arch.task.optimizing=Uygun hale getiriliyor {}
arch.task.sync_databases.waiting=Waiting for {}
arch.task.sync_sb.status={} güncelleniyor arch.task.sync_sb.status={} güncelleniyor
arch.uninstall.clean_cached.error=Diskte bulunan eski {} sürümleri kaldırılamadı arch.uninstall.clean_cached.error=Diskte bulunan eski {} sürümleri kaldırılamadı
arch.uninstall.clean_cached.substatus=Eski sürümler diskten kaldırılıyor arch.uninstall.clean_cached.substatus=Eski sürümler diskten kaldırılıyor

View File

@@ -13,11 +13,12 @@ import requests
from bauh.api.abstract.context import ApplicationContext from bauh.api.abstract.context import ApplicationContext
from bauh.api.abstract.handler import TaskManager from bauh.api.abstract.handler import TaskManager
from bauh.commons import system
from bauh.commons.boot import CreateConfigFile
from bauh.commons.html import bold from bauh.commons.html import bold
from bauh.commons.system import run_cmd, new_root_subprocess, ProcessHandler from bauh.commons.system import new_root_subprocess, ProcessHandler
from bauh.commons.util import datetime_as_milis
from bauh.gems.arch import pacman, disk, CUSTOM_MAKEPKG_FILE, CONFIG_DIR, AUR_INDEX_FILE, get_icon_path, database, \ from bauh.gems.arch import pacman, disk, CUSTOM_MAKEPKG_FILE, CONFIG_DIR, AUR_INDEX_FILE, get_icon_path, database, \
mirrors, ARCH_CACHE_PATH, BUILD_DIR, AUR_INDEX_TS_FILE mirrors, ARCH_CACHE_PATH, AUR_INDEX_TS_FILE, aur
from bauh.gems.arch.aur import URL_INDEX from bauh.gems.arch.aur import URL_INDEX
from bauh.view.util.translation import I18n from bauh.view.util.translation import I18n
@@ -31,18 +32,20 @@ RE_CLEAR_REPLACE = re.compile(r'[\-_.]')
class AURIndexUpdater(Thread): class AURIndexUpdater(Thread):
def __init__(self, context: ApplicationContext, taskman: TaskManager): def __init__(self, context: ApplicationContext, taskman: TaskManager, create_config: Optional[CreateConfigFile] = None, arch_config: Optional[dict] = None):
super(AURIndexUpdater, self).__init__(daemon=True) super(AURIndexUpdater, self).__init__(daemon=True)
self.http_client = context.http_client self.http_client = context.http_client
self.i18n = context.i18n self.i18n = context.i18n
self.logger = context.logger self.logger = context.logger
self.taskman = taskman self.taskman = taskman
self.task_id = 'index_aur' self.task_id = 'index_aur'
self.create_config = create_config
self.config = arch_config
self.taskman.register_task(self.task_id, self.i18n['arch.task.aur.index.status'], get_icon_path())
@staticmethod def should_update(self) -> bool:
def should_update(arch_config: dict) -> bool:
try: try:
exp_minutes = int(arch_config['aur_idx_exp']) exp_minutes = int(self.config['aur_idx_exp'])
except: except:
traceback.print_exc() traceback.print_exc()
return True return True
@@ -66,11 +69,9 @@ class AURIndexUpdater(Thread):
traceback.print_exc() traceback.print_exc()
return True return True
def run(self): def update_index(self):
ti = time.time()
self.logger.info('Indexing AUR packages') self.logger.info('Indexing AUR packages')
self.taskman.register_task(self.task_id, self.i18n['arch.task.aur.index.status'], get_icon_path()) self.taskman.update_progress(self.task_id, 5, self.i18n['arch.task.aur.index.substatus.download'])
self.taskman.update_progress(self.task_id, 1, self.i18n['arch.task.aur.index.substatus.download'])
try: try:
index_ts = datetime.utcnow().timestamp() index_ts = datetime.utcnow().timestamp()
res = self.http_client.get(URL_INDEX) res = self.http_client.get(URL_INDEX)
@@ -115,6 +116,22 @@ class AURIndexUpdater(Thread):
self.logger.warning('No internet connection: could not pre-index packages') self.logger.warning('No internet connection: could not pre-index packages')
self.taskman.update_progress(self.task_id, 100, self.i18n['arch.task.aur.index.substatus.error.download']) self.taskman.update_progress(self.task_id, 100, self.i18n['arch.task.aur.index.substatus.error.download'])
def run(self):
ti = time.time()
if self.create_config:
self.taskman.update_progress(self.task_id, 0, self.i18n['task.waiting_task'].format(self.create_config.task_name))
self.create_config.join()
self.config = self.create_config.config
self.taskman.update_progress(self.task_id, 1, self.i18n['arch.task.aur.index.substatus.checking'])
if self.should_update():
self.update_index()
else:
self.logger.info("AUR index is up to date. Aborting...")
self.taskman.update_progress(self.task_id, 100, None)
tf = time.time() tf = time.time()
self.taskman.finish_task(self.task_id) self.taskman.finish_task(self.task_id)
self.logger.info("Finished. Took {0:.2f} seconds".format(tf - ti)) self.logger.info("Finished. Took {0:.2f} seconds".format(tf - ti))
@@ -122,48 +139,56 @@ class AURIndexUpdater(Thread):
class ArchDiskCacheUpdater(Thread): class ArchDiskCacheUpdater(Thread):
def __init__(self, task_man: TaskManager, arch_config: dict, i18n: I18n, logger: logging.Logger, controller: "ArchManager", internet_available: bool, def __init__(self, taskman: TaskManager, i18n: I18n, logger: logging.Logger,
aur_supported: bool, aur_indexer: Thread): controller: "ArchManager", internet_available: bool, aur_indexer: Thread,
create_config: CreateConfigFile):
super(ArchDiskCacheUpdater, self).__init__(daemon=True) super(ArchDiskCacheUpdater, self).__init__(daemon=True)
self.logger = logger self.logger = logger
self.task_man = task_man self.taskman = taskman
self.task_id = 'arch_cache_up' self.task_id = 'arch_cache_up'
self.i18n = i18n self.i18n = i18n
self.indexed = 0 self.indexed = 0
self.indexed_template = self.i18n['arch.task.disk_cache.indexed'] + ': {}/ {}' self.indexed_template = self.i18n['arch.task.disk_cache.indexed'] + ': {}/ {}'
self.to_index = 0 self.to_index = 0
self.progress = 0 # progress is defined by the number of packages prepared and indexed self.progress = 0 # progress is defined by the number of packages prepared and indexed
self.repositories = arch_config['repositories']
self.aur = aur_supported
self.controller = controller self.controller = controller
self.internet_available = internet_available self.internet_available = internet_available
self.installed_hash_path = '{}/installed.sha1'.format(ARCH_CACHE_PATH) self.installed_hash_path = '{}/installed.sha1'.format(ARCH_CACHE_PATH)
self.installed_cache_dir = '{}/installed'.format(ARCH_CACHE_PATH) self.installed_cache_dir = '{}/installed'.format(ARCH_CACHE_PATH)
self.aur_indexer = aur_indexer self.aur_indexer = aur_indexer
self.create_config = create_config
self.taskman.register_task(self.task_id, self.i18n['arch.task.disk_cache'], get_icon_path())
def update_indexed(self, pkgname: str): def update_indexed(self, pkgname: str):
self.indexed += 1 self.indexed += 1
sub = self.indexed_template.format(self.indexed, self.to_index) sub = self.indexed_template.format(self.indexed, self.to_index)
progress = self.progress + (self.indexed / self.to_index) * 50 progress = self.progress + (self.indexed / self.to_index) * 50
self.task_man.update_progress(self.task_id, progress, sub) self.taskman.update_progress(self.task_id, progress, sub)
def _update_progress(self, progress: float, msg: str): def _update_progress(self, progress: float, msg: str):
self.progress = progress self.progress = progress
self.task_man.update_progress(self.task_id, self.progress, msg) self.taskman.update_progress(self.task_id, self.progress, msg)
def _notify_reading_files(self): def _notify_reading_files(self):
self._update_progress(50, self.i18n['arch.task.disk_cache.indexing']) self._update_progress(50, self.i18n['arch.task.disk_cache.indexing'])
def run(self): def run(self):
if not any([self.aur, self.repositories]): ti = time.time()
self.taskman.update_progress(self.task_id, 0, self.i18n['task.waiting_task'].format(self.create_config.task_name))
self.create_config.join()
config = self.create_config.config
aur_supported, repositories = aur.is_supported(config), config['repositories']
self.taskman.update_progress(self.task_id, 1, None)
if not any([aur_supported, repositories]):
self.taskman.update_progress(self.task_id, 100, self.i18n['arch.task.disabled'])
self.taskman.finish_task(self.task_id)
return return
ti = time.time()
self.task_man.register_task(self.task_id, self.i18n['arch.task.disk_cache'], get_icon_path())
self.logger.info("Checking already cached package data") self.logger.info("Checking already cached package data")
self._update_progress(1, self.i18n['arch.task.disk_cache.checking']) self._update_progress(1, self.i18n['arch.task.disk_cache.checking'])
cache_dirs = [fpath for fpath in glob.glob('{}/*'.format(self.installed_cache_dir)) if os.path.isdir(fpath)] cache_dirs = [fpath for fpath in glob.glob('{}/*'.format(self.installed_cache_dir)) if os.path.isdir(fpath)]
not_cached_names = None not_cached_names = None
@@ -177,8 +202,8 @@ class ArchDiskCacheUpdater(Thread):
self._update_progress(20, self.i18n['arch.task.disk_cache.checking']) self._update_progress(20, self.i18n['arch.task.disk_cache.checking'])
if not not_cached_names: if not not_cached_names:
self.task_man.update_progress(self.task_id, 100, '') self.taskman.update_progress(self.task_id, 100, '')
self.task_man.finish_task(self.task_id) self.taskman.finish_task(self.task_id)
tf = time.time() tf = time.time()
time_msg = '{0:.2f} seconds'.format(tf - ti) time_msg = '{0:.2f} seconds'.format(tf - ti)
self.logger.info('Finished: no package data to cache ({})'.format(time_msg)) self.logger.info('Finished: no package data to cache ({})'.format(time_msg))
@@ -186,8 +211,8 @@ class ArchDiskCacheUpdater(Thread):
self.logger.info('Pre-caching installed Arch packages data to disk') self.logger.info('Pre-caching installed Arch packages data to disk')
if self.aur and self.aur_indexer: if aur_supported and self.aur_indexer:
self.task_man.update_progress(self.task_id, 20, self.i18n['arch.task.disk_cache.waiting_aur_index'].format(bold(self.i18n['arch.task.aur.index.status']))) self.taskman.update_progress(self.task_id, 20, self.i18n['arch.task.disk_cache.waiting_aur_index'].format(bold(self.i18n['arch.task.aur.index.status'])))
self.aur_indexer.join() self.aur_indexer.join()
self._update_progress(21, self.i18n['arch.task.disk_cache.checking']) self._update_progress(21, self.i18n['arch.task.disk_cache.checking'])
@@ -199,7 +224,7 @@ class ArchDiskCacheUpdater(Thread):
saved = 0 saved = 0
pkgs = {p.name: p for p in installed if ((self.aur and p.repository == 'aur') or (self.repositories and p.repository != 'aur')) and not os.path.exists(p.get_disk_cache_path())} pkgs = {p.name: p for p in installed if ((aur_supported and p.repository == 'aur') or (repositories and p.repository != 'aur')) and not os.path.exists(p.get_disk_cache_path())}
self.to_index = len(pkgs) self.to_index = len(pkgs)
# overwrite == True because the verification already happened # overwrite == True because the verification already happened
@@ -207,8 +232,8 @@ class ArchDiskCacheUpdater(Thread):
saved += disk.write_several(pkgs=pkgs, saved += disk.write_several(pkgs=pkgs,
after_desktop_files=self._notify_reading_files, after_desktop_files=self._notify_reading_files,
after_written=self.update_indexed, overwrite=True) after_written=self.update_indexed, overwrite=True)
self.task_man.update_progress(self.task_id, 100, None) self.taskman.update_progress(self.task_id, 100, None)
self.task_man.finish_task(self.task_id) self.taskman.finish_task(self.task_id)
tf = time.time() tf = time.time()
time_msg = '{0:.2f} seconds'.format(tf - ti) time_msg = '{0:.2f} seconds'.format(tf - ti)
@@ -217,7 +242,7 @@ class ArchDiskCacheUpdater(Thread):
class ArchCompilationOptimizer(Thread): class ArchCompilationOptimizer(Thread):
def __init__(self, arch_config: dict, i18n: I18n, logger: logging.Logger, taskman: Optional[TaskManager] = None): def __init__(self, i18n: I18n, logger: logging.Logger, taskman: TaskManager, create_config: Optional[CreateConfigFile] = None):
super(ArchCompilationOptimizer, self).__init__(daemon=True) super(ArchCompilationOptimizer, self).__init__(daemon=True)
self.logger = logger self.logger = logger
self.i18n = i18n self.i18n = i18n
@@ -227,17 +252,12 @@ class ArchCompilationOptimizer(Thread):
self.re_ccache = re.compile(r'!?ccache') self.re_ccache = re.compile(r'!?ccache')
self.taskman = taskman self.taskman = taskman
self.task_id = 'arch_make_optm' self.task_id = 'arch_make_optm'
self.optimizations = bool(arch_config['optimize']) self.create_config = create_config
self.taskman.register_task(self.task_id, self.i18n['arch.task.optimizing'].format(bold('makepkg.conf')), get_icon_path())
def _is_ccache_installed(self) -> bool: def _is_ccache_installed(self) -> bool:
return bool(run_cmd('which ccache', print_error=False)) code, _ = system.execute(cmd='which ccache', output=False)
return code == 0
def _update_progress(self, progress: float, substatus: str = None):
if self.taskman:
self.taskman.update_progress(self.task_id, progress, substatus)
if progress == 100:
self.taskman.finish_task(self.task_id)
def optimize(self): def optimize(self):
ti = time.time() ti = time.time()
@@ -271,7 +291,7 @@ class ArchCompilationOptimizer(Thread):
else: else:
optimizations.append('MAKEFLAGS="-j$(nproc)"') optimizations.append('MAKEFLAGS="-j$(nproc)"')
self._update_progress(20) self.taskman.update_progress(self.task_id, 20, None)
compress_xz = self.re_compress_xz.findall(custom_makepkg or global_makepkg) compress_xz = self.re_compress_xz.findall(custom_makepkg or global_makepkg)
@@ -286,7 +306,7 @@ class ArchCompilationOptimizer(Thread):
else: else:
optimizations.append('COMPRESSXZ=(xz -c -z - --threads=0)') optimizations.append('COMPRESSXZ=(xz -c -z - --threads=0)')
self._update_progress(40) self.taskman.update_progress(self.task_id, 40, None)
compress_zst = self.re_compress_zst.findall(custom_makepkg or global_makepkg) compress_zst = self.re_compress_zst.findall(custom_makepkg or global_makepkg)
@@ -301,7 +321,7 @@ class ArchCompilationOptimizer(Thread):
else: else:
optimizations.append('COMPRESSZST=(zstd -c -z -q - --threads=0)') optimizations.append('COMPRESSZST=(zstd -c -z -q - --threads=0)')
self._update_progress(60) self.taskman.update_progress(self.task_id, 60, None)
build_envs = self.re_build_env.findall(custom_makepkg or global_makepkg) build_envs = self.re_build_env.findall(custom_makepkg or global_makepkg)
@@ -331,7 +351,7 @@ class ArchCompilationOptimizer(Thread):
self.logger.info('Adding a BUILDENV declaration') self.logger.info('Adding a BUILDENV declaration')
optimizations.append('BUILDENV=(ccache)') optimizations.append('BUILDENV=(ccache)')
self._update_progress(80) self.taskman.update_progress(self.task_id, 80, None)
if custom_makepkg and optimizations: if custom_makepkg and optimizations:
generated_by = '# <generated by bauh>\n' generated_by = '# <generated by bauh>\n'
@@ -348,43 +368,91 @@ class ArchCompilationOptimizer(Thread):
self.logger.info("Removing old optimized 'makepkg.conf' at '{}'".format(CUSTOM_MAKEPKG_FILE)) self.logger.info("Removing old optimized 'makepkg.conf' at '{}'".format(CUSTOM_MAKEPKG_FILE))
os.remove(CUSTOM_MAKEPKG_FILE) os.remove(CUSTOM_MAKEPKG_FILE)
self.taskman.update_progress(self.task_id, 100, None)
tf = time.time() tf = time.time()
self._update_progress(100) self.logger.info('Finished. {0:.2f} seconds'.format(tf - ti))
self.logger.info("Optimizations took {0:.2f} seconds".format(tf - ti))
self.logger.info('Finished')
def run(self): def run(self):
if not self.optimizations: ti = time.time()
self.logger.info("Arch packages compilation optimizations are disabled") if self.create_config:
self.taskman.update_progress(self.task_id, 0, self.i18n['task.waiting_task'].format(bold(self.create_config.task_name)))
self.create_config.join()
if os.path.exists(CUSTOM_MAKEPKG_FILE): self.taskman.update_progress(self.task_id, 1, None)
self.logger.info("Removing custom 'makepkg.conf' -> '{}'".format(CUSTOM_MAKEPKG_FILE))
os.remove(CUSTOM_MAKEPKG_FILE)
self.logger.info('Finished') if self.create_config.config['optimize'] and aur.is_supported(self.create_config.config):
else: try:
if self.taskman: self.optimize()
self.taskman.register_task(self.task_id, self.i18n['arch.task.optimizing'].format(bold('makepkg.conf')), get_icon_path()) except:
self.logger.error("Unexpected exception")
traceback.print_exc()
self.taskman.update_progress(self.task_id, 100, None)
else:
self.logger.info("AUR packages compilation optimizations are disabled")
self.optimize() if os.path.exists(CUSTOM_MAKEPKG_FILE):
try:
self.logger.info("Removing custom 'makepkg.conf' -> '{}'".format(CUSTOM_MAKEPKG_FILE))
os.remove(CUSTOM_MAKEPKG_FILE)
except:
self.logger.error("Unexpected exception")
traceback.print_exc()
self.taskman.update_progress(self.task_id, 100, self.i18n['arch.task.disabled'])
tf = time.time()
self.taskman.finish_task(self.task_id)
self.logger.info('Finished. Took {0:.2f} seconds'.format(tf - ti))
class RefreshMirrors(Thread): class RefreshMirrors(Thread):
def __init__(self, taskman: TaskManager, root_password: str, i18n: I18n, sort_limit: int, logger: logging.Logger): def __init__(self, taskman: TaskManager, root_password: str, i18n: I18n, logger: logging.Logger,
create_config: CreateConfigFile):
super(RefreshMirrors, self).__init__(daemon=True) super(RefreshMirrors, self).__init__(daemon=True)
self.taskman = taskman self.taskman = taskman
self.i18n = i18n self.i18n = i18n
self.logger = logger self.logger = logger
self.root_password = root_password self.root_password = root_password
self.task_id = "arch_mirrors" self.task_id = "arch_mirrors"
self.sort_limit = sort_limit self.create_config = create_config
self.refreshed = False
self.task_name = self.i18n['arch.task.mirrors']
self.taskman.register_task(self.task_id, self.task_name, get_icon_path())
def _notify_output(self, output: str): def _notify_output(self, output: str):
self.taskman.update_output(self.task_id, output) self.taskman.update_output(self.task_id, output)
@staticmethod
def is_enabled(arch_config: dict, aur_supported: bool) -> bool:
return (arch_config['repositories'] or aur_supported) \
and arch_config['refresh_mirrors_startup'] and pacman.is_mirrors_available()
@classmethod
def should_synchronize(cls, arch_config: dict, aur_supported: bool, logger: logging.Logger) -> bool:
return cls.is_enabled(arch_config, aur_supported) and mirrors.should_sync(logger)
def run(self): def run(self):
self.taskman.register_task(self.task_id, self.i18n['arch.task.mirrors'], get_icon_path()) ti = time.time()
self.taskman.update_progress(self.task_id, 0, self.i18n['task.waiting_task'].format(bold(self.create_config.task_name)))
self.create_config.join()
arch_config = self.create_config.config
aur_supported = aur.is_supported(arch_config)
self.taskman.update_progress(self.task_id, 1, self.i18n['arch.task.checking_settings'])
if not self.is_enabled(arch_config, aur_supported):
self.taskman.update_progress(self.task_id, 100, self.i18n['arch.task.disabled'])
self.taskman.finish_task(self.task_id)
return
if not mirrors.should_sync(self.logger):
self.taskman.update_progress(self.task_id, 100, self.i18n['arch.task.mirrors.cached'])
self.taskman.finish_task(self.task_id)
return
sort_limit = arch_config['mirrors_sort_limit']
self.logger.info("Refreshing mirrors") self.logger.info("Refreshing mirrors")
handler = ProcessHandler() handler = ProcessHandler()
@@ -394,15 +462,16 @@ class RefreshMirrors(Thread):
if success: if success:
if self.sort_limit is not None and self.sort_limit >= 0: if sort_limit is not None and sort_limit >= 0:
self.taskman.update_progress(self.task_id, 50, self.i18n['arch.custom_action.refresh_mirrors.status.updating']) self.taskman.update_progress(self.task_id, 50, self.i18n['arch.custom_action.refresh_mirrors.status.updating'])
try: try:
handler.handle_simple(pacman.sort_fastest_mirrors(self.root_password, self.sort_limit), output_handler=self._notify_output) handler.handle_simple(pacman.sort_fastest_mirrors(self.root_password, sort_limit), output_handler=self._notify_output)
except: except:
self.logger.error("Could not sort mirrors by speed") self.logger.error("Could not sort mirrors by speed")
traceback.print_exc() traceback.print_exc()
mirrors.register_sync(self.logger) mirrors.register_sync(self.logger)
self.refreshed = True
else: else:
self.logger.error("It was not possible to refresh mirrors") self.logger.error("It was not possible to refresh mirrors")
except: except:
@@ -411,12 +480,14 @@ class RefreshMirrors(Thread):
self.taskman.update_progress(self.task_id, 100, None) self.taskman.update_progress(self.task_id, 100, None)
self.taskman.finish_task(self.task_id) self.taskman.finish_task(self.task_id)
self.logger.info("Finished") tf = time.time()
self.logger.info("Finished. Took {0:.2f} seconds".format(tf - ti))
class SyncDatabases(Thread): class SyncDatabases(Thread):
def __init__(self, taskman: TaskManager, root_password: str, i18n: I18n, logger: logging.Logger, refresh_mirrors: RefreshMirrors = None): def __init__(self, taskman: TaskManager, root_password: str, i18n: I18n, logger: logging.Logger,
refresh_mirrors: RefreshMirrors, create_config: CreateConfigFile):
super(SyncDatabases, self).__init__(daemon=True) super(SyncDatabases, self).__init__(daemon=True)
self.task_man = taskman self.task_man = taskman
self.i18n = i18n self.i18n = i18n
@@ -425,15 +496,46 @@ class SyncDatabases(Thread):
self.root_password = root_password self.root_password = root_password
self.refresh_mirrors = refresh_mirrors self.refresh_mirrors = refresh_mirrors
self.logger = logger self.logger = logger
self.create_config = create_config
self.task_name = self.i18n['arch.sync_databases.substatus']
self.taskman.register_task(self.task_id, self.task_name, get_icon_path())
self.synchronized = False
@staticmethod
def is_enabled(arch_config: dict, aur_supported: bool) -> bool:
return arch_config['sync_databases_startup'] and (aur_supported or arch_config['repositories'])
@classmethod
def should_sync(cls, mirrors_refreshed: bool, arch_config: dict, aur_supported: bool, logger: logging.Logger):
return mirrors_refreshed or (cls.is_enabled(arch_config, aur_supported) and database.should_sync(arch_config, aur_supported, None, logger))
def run(self) -> None: def run(self) -> None:
self.taskman.update_progress(self.task_id, 0, self.i18n['task.waiting_task'].format(bold(self.create_config.task_name)))
self.create_config.join()
self.taskman.update_progress(self.task_id, 0, self.i18n['task.waiting_task'].format(bold(self.refresh_mirrors.task_name)))
self.refresh_mirrors.join()
self.taskman.update_progress(self.task_id, 1, self.i18n['arch.task.checking_settings'])
arch_config = self.create_config.config
aur_supported = aur.is_supported(arch_config)
if not self.is_enabled(arch_config, aur_supported):
self.taskman.update_progress(self.task_id, 100, self.i18n['arch.task.disabled'])
self.taskman.finish_task(self.task_id)
return
shoud_sync = self.refresh_mirrors.refreshed or (database.should_sync(arch_config, aur_supported, None, self.logger))
if not shoud_sync:
self.taskman.update_progress(self.task_id, 100, self.i18n['arch.sync_databases.substatus.synchronized'])
self.taskman.finish_task(self.task_id)
self.synchronized = True
return
self.logger.info("Synchronizing databases") self.logger.info("Synchronizing databases")
self.taskman.register_task(self.task_id, self.i18n['arch.sync_databases.substatus'], get_icon_path()) self.taskman.register_task(self.task_id, self.i18n['arch.sync_databases.substatus'], get_icon_path())
if self.refresh_mirrors and self.refresh_mirrors.is_alive():
self.taskman.update_progress(self.task_id, 0, self.i18n['arch.task.sync_databases.waiting'].format('"{}"'.format(self.i18n['arch.task.mirrors'])))
self.refresh_mirrors.join()
progress = 10 progress = 10
dbs = pacman.get_databases() dbs = pacman.get_databases()
self.taskman.update_progress(self.task_id, progress, None) self.taskman.update_progress(self.task_id, progress, None)
@@ -472,6 +574,7 @@ class SyncDatabases(Thread):
if p.returncode == 0: if p.returncode == 0:
database.register_sync(self.logger) database.register_sync(self.logger)
self.synchronized = True
else: else:
self.logger.error("Could not synchronize database") self.logger.error("Could not synchronize database")

View File

@@ -2,6 +2,7 @@ import os
from pathlib import Path from pathlib import Path
from bauh.api.constants import CONFIG_PATH from bauh.api.constants import CONFIG_PATH
from bauh.commons import resource
ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
SUGGESTIONS_FILE = 'https://raw.githubusercontent.com/vinifmor/bauh-files/master/flatpak/suggestions.txt' SUGGESTIONS_FILE = 'https://raw.githubusercontent.com/vinifmor/bauh-files/master/flatpak/suggestions.txt'
@@ -9,3 +10,7 @@ CONFIG_FILE = '{}/flatpak.yml'.format(CONFIG_PATH)
CONFIG_DIR = '{}/flatpak'.format(CONFIG_PATH) CONFIG_DIR = '{}/flatpak'.format(CONFIG_PATH)
UPDATES_IGNORED_FILE = '{}/updates_ignored.txt'.format(CONFIG_DIR) UPDATES_IGNORED_FILE = '{}/updates_ignored.txt'.format(CONFIG_DIR)
EXPORTS_PATH = '{}/.local/share/flatpak/exports/share'.format(str(Path.home())) EXPORTS_PATH = '{}/.local/share/flatpak/exports/share'.format(str(Path.home()))
def get_icon_path() -> str:
return resource.get_path('img/flatpak.svg', ROOT_DIR)

View File

@@ -1,7 +1,11 @@
from bauh.commons.config import read_config as read from bauh.commons.config import YAMLConfigManager
from bauh.gems.flatpak import CONFIG_FILE from bauh.gems.flatpak import CONFIG_FILE
def read_config(update_file: bool = False) -> dict: class FlatpakConfigManager(YAMLConfigManager):
template = {'installation_level': None}
return read(CONFIG_FILE, template, update_file=update_file) def __init__(self):
super(FlatpakConfigManager, self).__init__(config_file_path=CONFIG_FILE)
def get_default_config(self) -> dict:
return {'installation_level': None}

View File

@@ -16,11 +16,12 @@ from bauh.api.abstract.model import PackageHistory, PackageUpdate, SoftwarePacka
from bauh.api.abstract.view import MessageType, FormComponent, SingleSelectComponent, InputOption, SelectViewType, \ from bauh.api.abstract.view import MessageType, FormComponent, SingleSelectComponent, InputOption, SelectViewType, \
ViewComponent, PanelComponent ViewComponent, PanelComponent
from bauh.commons import user from bauh.commons import user
from bauh.commons.config import save_config from bauh.commons.boot import CreateConfigFile
from bauh.commons.html import strip_html, bold from bauh.commons.html import strip_html, bold
from bauh.commons.system import ProcessHandler from bauh.commons.system import ProcessHandler
from bauh.gems.flatpak import flatpak, SUGGESTIONS_FILE, CONFIG_FILE, UPDATES_IGNORED_FILE, CONFIG_DIR, EXPORTS_PATH from bauh.gems.flatpak import flatpak, SUGGESTIONS_FILE, CONFIG_FILE, UPDATES_IGNORED_FILE, CONFIG_DIR, EXPORTS_PATH, \
from bauh.gems.flatpak.config import read_config get_icon_path
from bauh.gems.flatpak.config import FlatpakConfigManager
from bauh.gems.flatpak.constants import FLATHUB_API_URL from bauh.gems.flatpak.constants import FLATHUB_API_URL
from bauh.gems.flatpak.model import FlatpakApplication from bauh.gems.flatpak.model import FlatpakApplication
from bauh.gems.flatpak.worker import FlatpakAsyncDataLoader, FlatpakUpdateLoader from bauh.gems.flatpak.worker import FlatpakAsyncDataLoader, FlatpakUpdateLoader
@@ -41,6 +42,7 @@ class FlatpakManager(SoftwareManager):
self.http_client = context.http_client self.http_client = context.http_client
self.suggestions_cache = context.cache_factory.new() self.suggestions_cache = context.cache_factory.new()
self.logger = context.logger self.logger = context.logger
self.configman = FlatpakConfigManager()
def get_managed_types(self) -> Set["type"]: def get_managed_types(self) -> Set["type"]:
return {FlatpakApplication} return {FlatpakApplication}
@@ -337,9 +339,9 @@ class FlatpakManager(SoftwareManager):
return True return True
def install(self, pkg: FlatpakApplication, root_password: str, disk_loader: DiskCacheLoader, watcher: ProcessWatcher) -> TransactionResult: def install(self, pkg: FlatpakApplication, root_password: str, disk_loader: DiskCacheLoader, watcher: ProcessWatcher) -> TransactionResult:
config = read_config() flatpak_config = self.configman.get_config()
install_level = config['installation_level'] install_level = flatpak_config['installation_level']
if install_level is not None: if install_level is not None:
self.logger.info("Default Flaptak installation level defined: {}".format(install_level)) self.logger.info("Default Flaptak installation level defined: {}".format(install_level))
@@ -453,7 +455,8 @@ class FlatpakManager(SoftwareManager):
return action == SoftwareAction.DOWNGRADE and pkg.installation == 'system' return action == SoftwareAction.DOWNGRADE and pkg.installation == 'system'
def prepare(self, task_manager: TaskManager, root_password: str, internet_available: bool): def prepare(self, task_manager: TaskManager, root_password: str, internet_available: bool):
Thread(target=read_config, args=(True,), daemon=True).start() CreateConfigFile(taskman=task_manager, configman=self.configman, i18n=self.i18n,
task_icon_path=get_icon_path(), logger=self.logger).start()
def list_updates(self, internet_available: bool) -> List[PackageUpdate]: def list_updates(self, internet_available: bool) -> List[PackageUpdate]:
updates = [] updates = []
@@ -555,7 +558,7 @@ class FlatpakManager(SoftwareManager):
def get_settings(self, screen_width: int, screen_height: int) -> ViewComponent: def get_settings(self, screen_width: int, screen_height: int) -> ViewComponent:
fields = [] fields = []
config = read_config() flatpak_config = self.configman.get_config()
install_opts = [InputOption(label=self.i18n['flatpak.config.install_level.system'].capitalize(), install_opts = [InputOption(label=self.i18n['flatpak.config.install_level.system'].capitalize(),
value='system', value='system',
@@ -568,7 +571,7 @@ class FlatpakManager(SoftwareManager):
tooltip=self.i18n['flatpak.config.install_level.ask.tip'].format(app=self.context.app_name))] tooltip=self.i18n['flatpak.config.install_level.ask.tip'].format(app=self.context.app_name))]
fields.append(SingleSelectComponent(label=self.i18n['flatpak.config.install_level'], fields.append(SingleSelectComponent(label=self.i18n['flatpak.config.install_level'],
options=install_opts, options=install_opts,
default_option=[o for o in install_opts if o.value == config['installation_level']][0], default_option=[o for o in install_opts if o.value == flatpak_config['installation_level']][0],
max_per_line=len(install_opts), max_per_line=len(install_opts),
max_width=floor(screen_width * 0.22), max_width=floor(screen_width * 0.22),
type_=SelectViewType.RADIO)) type_=SelectViewType.RADIO))
@@ -576,11 +579,11 @@ class FlatpakManager(SoftwareManager):
return PanelComponent([FormComponent(fields, self.i18n['installation'].capitalize())]) return PanelComponent([FormComponent(fields, self.i18n['installation'].capitalize())])
def save_settings(self, component: PanelComponent) -> Tuple[bool, Optional[List[str]]]: def save_settings(self, component: PanelComponent) -> Tuple[bool, Optional[List[str]]]:
config = read_config() flatpak_config = self.configman.get_config()
config['installation_level'] = component.components[0].components[0].get_selected() flatpak_config['installation_level'] = component.components[0].components[0].get_selected()
try: try:
save_config(config, CONFIG_FILE) self.configman.save_config(flatpak_config)
return True, None return True, None
except: except:
return False, [traceback.format_exc()] return False, [traceback.format_exc()]

View File

@@ -1,7 +1,11 @@
from bauh.commons.config import read_config as read from bauh.commons.config import YAMLConfigManager
from bauh.gems.snap import CONFIG_FILE from bauh.gems.snap import CONFIG_FILE
def read_config(update_file: bool = False) -> dict: class SnapConfigManager(YAMLConfigManager):
template = {'install_channel': False, 'categories_exp': 24}
return read(CONFIG_FILE, template, update_file=update_file) def __init__(self):
super(SnapConfigManager, self).__init__(config_file_path=CONFIG_FILE)
def get_default_config(self) -> dict:
return {'install_channel': False, 'categories_exp': 24}

View File

@@ -14,14 +14,14 @@ from bauh.api.abstract.view import SingleSelectComponent, SelectViewType, InputO
FormComponent, TextInputComponent FormComponent, TextInputComponent
from bauh.api.exception import NoInternetException from bauh.api.exception import NoInternetException
from bauh.commons import resource from bauh.commons import resource
from bauh.commons.boot import CreateConfigFile
from bauh.commons.category import CategoriesDownloader from bauh.commons.category import CategoriesDownloader
from bauh.commons.config import save_config
from bauh.commons.html import bold from bauh.commons.html import bold
from bauh.commons.system import SystemProcess, ProcessHandler, new_root_subprocess, get_human_size_str from bauh.commons.system import SystemProcess, ProcessHandler, new_root_subprocess, get_human_size_str
from bauh.commons.view_utils import new_select from bauh.commons.view_utils import new_select
from bauh.gems.snap import snap, URL_CATEGORIES_FILE, CATEGORIES_FILE_PATH, SUGGESTIONS_FILE, \ from bauh.gems.snap import snap, URL_CATEGORIES_FILE, CATEGORIES_FILE_PATH, SUGGESTIONS_FILE, \
get_icon_path, snapd, CONFIG_FILE, ROOT_DIR get_icon_path, snapd, ROOT_DIR
from bauh.gems.snap.config import read_config from bauh.gems.snap.config import SnapConfigManager
from bauh.gems.snap.model import SnapApplication from bauh.gems.snap.model import SnapApplication
from bauh.gems.snap.snapd import SnapdClient from bauh.gems.snap.snapd import SnapdClient
@@ -42,6 +42,7 @@ class SnapManager(SoftwareManager):
self.categories = {} self.categories = {}
self.suggestions_cache = context.cache_factory.new() self.suggestions_cache = context.cache_factory.new()
self.info_path = None self.info_path = None
self.configman = SnapConfigManager()
self.custom_actions = [ self.custom_actions = [
CustomSoftwareAction(i18n_status_key='snap.action.refresh.status', CustomSoftwareAction(i18n_status_key='snap.action.refresh.status',
i18n_label_key='snap.action.refresh.label', i18n_label_key='snap.action.refresh.label',
@@ -187,7 +188,7 @@ class SnapManager(SoftwareManager):
installed_names = {s['name'] for s in SnapdClient(self.logger).list_all_snaps()} installed_names = {s['name'] for s in SnapdClient(self.logger).list_all_snaps()}
client = SnapdClient(self.logger) client = SnapdClient(self.logger)
snap_config = read_config() snap_config = self.configman.get_config()
try: try:
channel = self._request_channel_installation(pkg=pkg, snap_config=snap_config, snapd_client=client, watcher=watcher) channel = self._request_channel_installation(pkg=pkg, snap_config=snap_config, snapd_client=client, watcher=watcher)
@@ -283,27 +284,35 @@ class SnapManager(SoftwareManager):
except: except:
return False return False
def _start_category_task(self, task_man: TaskManager): def _start_category_task(self, taskman: TaskManager, create_config: CreateConfigFile, downloader: CategoriesDownloader):
if task_man: if taskman:
task_man.register_task('snap_cats', self.i18n['task.download_categories'], get_icon_path()) taskman.update_progress('snap_cats', 0, self.i18n['task.waiting_task'].format(bold(create_config.task_name)))
task_man.update_progress('snap_cats', 50, None) create_config.join()
def _finish_category_task(self, task_man: TaskManager): categories_exp = create_config.config['categories_exp']
if task_man: downloader.expiration = categories_exp if isinstance(categories_exp, int) else None
task_man.update_progress('snap_cats', 100, None) taskman.update_progress('snap_cats', 1, None)
task_man.finish_task('snap_cats')
def _finish_category_task(self, taskman: TaskManager):
if taskman:
taskman.update_progress('snap_cats', 100, None)
taskman.finish_task('snap_cats')
def prepare(self, task_manager: TaskManager, root_password: str, internet_available: bool): def prepare(self, task_manager: TaskManager, root_password: str, internet_available: bool):
snap_config = read_config() create_config = CreateConfigFile(taskman=task_manager, configman=self.configman, i18n=self.i18n,
task_icon_path=get_icon_path(), logger=self.logger)
create_config.start()
CategoriesDownloader(id_='snap', manager=self, http_client=self.http_client, logger=self.logger, task_manager.register_task('snap_cats', self.i18n['task.download_categories'], get_icon_path())
url_categories_file=URL_CATEGORIES_FILE, category_downloader = CategoriesDownloader(id_='snap', manager=self, http_client=self.http_client,
categories_path=CATEGORIES_FILE_PATH, logger=self.logger,
expiration=snap_config['categories_exp'] if isinstance(snap_config['categories_exp'], int) else 0, url_categories_file=URL_CATEGORIES_FILE,
internet_connection=internet_available, categories_path=CATEGORIES_FILE_PATH,
internet_checker=self.context.internet_checker, internet_connection=internet_available,
before=lambda: self._start_category_task(task_manager), internet_checker=self.context.internet_checker,
after=lambda: self._finish_category_task(task_manager)).start() after=lambda: self._finish_category_task(task_manager))
category_downloader.before = lambda: self._start_category_task(task_manager, create_config, category_downloader)
category_downloader.start()
def list_updates(self, internet_available: bool) -> List[PackageUpdate]: def list_updates(self, internet_available: bool) -> List[PackageUpdate]:
pass pass
@@ -436,7 +445,7 @@ class SnapManager(SoftwareManager):
return pkg.screenshots if pkg.has_screenshots() else [] return pkg.screenshots if pkg.has_screenshots() else []
def get_settings(self, screen_width: int, screen_height: int) -> ViewComponent: def get_settings(self, screen_width: int, screen_height: int) -> ViewComponent:
snap_config = read_config() snap_config = self.configman.get_config()
max_width = 200 max_width = 200
install_channel = new_select(label=self.i18n['snap.config.install_channel'], install_channel = new_select(label=self.i18n['snap.config.install_channel'],
@@ -457,14 +466,14 @@ class SnapManager(SoftwareManager):
return PanelComponent([FormComponent([install_channel, categories_exp], self.i18n['installation'].capitalize())]) return PanelComponent([FormComponent([install_channel, categories_exp], self.i18n['installation'].capitalize())])
def save_settings(self, component: ViewComponent) -> Tuple[bool, Optional[List[str]]]: def save_settings(self, component: ViewComponent) -> Tuple[bool, Optional[List[str]]]:
config = read_config() snap_config = self.configman.get_config()
panel = component.components[0] panel = component.components[0]
config['install_channel'] = panel.get_component('snap_install_channel').get_selected() snap_config['install_channel'] = panel.get_component('snap_install_channel').get_selected()
config['categories_exp'] = panel.get_component('snap_cat_exp').get_int_value() snap_config['categories_exp'] = panel.get_component('snap_cat_exp').get_int_value()
try: try:
save_config(config, CONFIG_FILE) self.configman.save_config(snap_config)
return True, None return True, None
except: except:
return False, [traceback.format_exc()] return False, [traceback.format_exc()]

View File

@@ -1,16 +1,17 @@
from bauh.commons.config import read_config as read from bauh.commons.config import YAMLConfigManager
from bauh.gems.web import CONFIG_FILE from bauh.gems.web import CONFIG_FILE
def read_config(update_file: bool = False) -> dict: class WebConfigManager(YAMLConfigManager):
default_config = {
'environment': { def __init__(self):
'system': False, super(WebConfigManager, self).__init__(config_file_path=CONFIG_FILE)
'electron': {'version': None},
'cache_exp': 1440 def get_default_config(self) -> dict:
return {
'environment': {
'system': False,
'electron': {'version': None},
'cache_exp': 1440
}
} }
}
return read(CONFIG_FILE, default_config, update_file)

View File

@@ -28,15 +28,17 @@ from bauh.api.abstract.view import MessageType, MultipleSelectComponent, InputOp
SelectViewType, TextInputComponent, FormComponent, FileChooserComponent, ViewComponent, PanelComponent SelectViewType, TextInputComponent, FormComponent, FileChooserComponent, ViewComponent, PanelComponent
from bauh.api.constants import DESKTOP_ENTRIES_DIR from bauh.api.constants import DESKTOP_ENTRIES_DIR
from bauh.commons import resource from bauh.commons import resource
from bauh.commons.config import save_config from bauh.commons.boot import CreateConfigFile
from bauh.commons.html import bold from bauh.commons.html import bold
from bauh.commons.system import ProcessHandler, get_dir_size, get_human_size_str, SimpleProcess from bauh.commons.system import ProcessHandler, get_dir_size, get_human_size_str, SimpleProcess
from bauh.gems.web import INSTALLED_PATH, nativefier, DESKTOP_ENTRY_PATH_PATTERN, URL_FIX_PATTERN, ENV_PATH, UA_CHROME, \ from bauh.gems.web import INSTALLED_PATH, nativefier, DESKTOP_ENTRY_PATH_PATTERN, URL_FIX_PATTERN, ENV_PATH, UA_CHROME, \
SEARCH_INDEX_FILE, SUGGESTIONS_CACHE_FILE, ROOT_DIR, CONFIG_FILE, TEMP_PATH, FIXES_PATH, ELECTRON_PATH SEARCH_INDEX_FILE, SUGGESTIONS_CACHE_FILE, ROOT_DIR, TEMP_PATH, FIXES_PATH, ELECTRON_PATH, \
from bauh.gems.web.config import read_config get_icon_path
from bauh.gems.web.config import WebConfigManager
from bauh.gems.web.environment import EnvironmentUpdater, EnvironmentComponent from bauh.gems.web.environment import EnvironmentUpdater, EnvironmentComponent
from bauh.gems.web.model import WebApplication from bauh.gems.web.model import WebApplication
from bauh.gems.web.worker import SuggestionsDownloader, SearchIndexGenerator from bauh.gems.web.worker import SuggestionsManager, UpdateEnvironmentSettings, \
SuggestionsLoader, SearchIndexGenerator
try: try:
from bs4 import BeautifulSoup, SoupStrainer from bs4 import BeautifulSoup, SoupStrainer
@@ -58,7 +60,7 @@ RE_SYMBOLS_SPLIT = re.compile(r'[\-|_\s:.]')
class WebApplicationManager(SoftwareManager): class WebApplicationManager(SoftwareManager):
def __init__(self, context: ApplicationContext, suggestions_downloader: Thread = None): def __init__(self, context: ApplicationContext, suggestions_loader: Optional[SuggestionsLoader] = None):
super(WebApplicationManager, self).__init__(context=context) super(WebApplicationManager, self).__init__(context=context)
self.http_client = context.http_client self.http_client = context.http_client
self.env_updater = EnvironmentUpdater(logger=context.logger, http_client=context.http_client, self.env_updater = EnvironmentUpdater(logger=context.logger, http_client=context.http_client,
@@ -67,8 +69,9 @@ class WebApplicationManager(SoftwareManager):
self.i18n = context.i18n self.i18n = context.i18n
self.logger = context.logger self.logger = context.logger
self.env_thread = None self.env_thread = None
self.suggestions_downloader = suggestions_downloader self.suggestions_loader = suggestions_loader
self.suggestions = {} self.suggestions = {}
self.configman = WebConfigManager()
self.custom_actions = [CustomSoftwareAction(i18n_label_key='web.custom_action.clean_env', self.custom_actions = [CustomSoftwareAction(i18n_label_key='web.custom_action.clean_env',
i18n_status_key='web.custom_action.clean_env.status', i18n_status_key='web.custom_action.clean_env.status',
manager=self, manager=self,
@@ -254,8 +257,8 @@ class WebApplicationManager(SoftwareManager):
index = self._read_search_index() index = self._read_search_index()
if not index and self.suggestions_downloader and self.suggestions_downloader.is_alive(): if not index and self.suggestions_loader and self.suggestions_loader.is_alive():
self.suggestions_downloader.join() self.suggestions_loader.join()
index = self._read_search_index() index = self._read_search_index()
if index: if index:
@@ -634,7 +637,7 @@ class WebApplicationManager(SoftwareManager):
watcher.change_substatus(self.i18n['web.env.checking']) watcher.change_substatus(self.i18n['web.env.checking'])
handler = ProcessHandler(watcher) handler = ProcessHandler(watcher)
web_config = read_config() web_config = self.configman.get_config()
env_settings = self.env_updater.read_settings(web_config=web_config) env_settings = self.env_updater.read_settings(web_config=web_config)
if web_config['environment']['system'] and not nativefier.is_available(): if web_config['environment']['system'] and not nativefier.is_available():
@@ -796,7 +799,7 @@ class WebApplicationManager(SoftwareManager):
def can_work(self) -> bool: def can_work(self) -> bool:
if BS4_AVAILABLE and LXML_AVAILABLE: if BS4_AVAILABLE and LXML_AVAILABLE:
config = read_config(update_file=True) config = self.configman.get_config()
use_system_env = config['environment']['system'] use_system_env = config['environment']['system']
if not use_system_env: if not use_system_env:
@@ -809,28 +812,37 @@ class WebApplicationManager(SoftwareManager):
def requires_root(self, action: SoftwareAction, pkg: SoftwarePackage) -> bool: def requires_root(self, action: SoftwareAction, pkg: SoftwarePackage) -> bool:
return False return False
def _download_suggestions(self, downloader: SuggestionsDownloader): def _assign_suggestions(self, suggestions: dict):
self.suggestions = downloader.download() self.suggestions = suggestions
if self.suggestions:
index_gen = SearchIndexGenerator(logger=self.logger)
Thread(target=index_gen.generate_index, args=(self.suggestions,), daemon=True).start()
def prepare(self, task_manager: TaskManager, root_password: str, internet_available: bool): def prepare(self, task_manager: TaskManager, root_password: str, internet_available: bool):
create_config = CreateConfigFile(taskman=task_manager, configman=self.configman, i18n=self.i18n,
task_icon_path=get_icon_path(), logger=self.logger)
create_config.start()
if internet_available: if internet_available:
downloader = SuggestionsDownloader(logger=self.logger, http_client=self.http_client, UpdateEnvironmentSettings(env_updater=EnvironmentUpdater(logger=self.context.logger,
i18n=self.i18n, taskman=task_manager) i18n=self.i18n,
downloader.register_task() http_client=self.http_client,
file_downloader=self.context.file_downloader,
taskman=task_manager),
taskman=task_manager,
create_config=create_config,
i18n=self.i18n).start()
self.suggestions_downloader = Thread(target=self._download_suggestions, args=(downloader,), daemon=True) self.suggestions_loader = SuggestionsLoader(manager=SuggestionsManager(logger=self.logger,
self.suggestions_downloader.start() http_client=self.http_client,
i18n=self.i18n),
logger=self.logger,
i18n=self.i18n,
taskman=task_manager,
suggestions_callback=self._assign_suggestions)
self.suggestions_loader.start()
web_config = read_config() SearchIndexGenerator(taskman=task_manager,
suggestions_loader=self.suggestions_loader,
if self.env_updater.should_download_settings(web_config): i18n=self.i18n,
self.env_updater.register_task_read_settings(taskman=task_manager) logger=self.logger).start()
self.env_thread = Thread(target=self.env_updater.read_settings, args=(web_config, False, task_manager), daemon=True)
self.env_thread.start()
def list_updates(self, internet_available: bool) -> List[PackageUpdate]: def list_updates(self, internet_available: bool) -> List[PackageUpdate]:
pass pass
@@ -893,7 +905,7 @@ class WebApplicationManager(SoftwareManager):
return PackageSuggestion(priority=SuggestionPriority(suggestion['priority']), package=app) return PackageSuggestion(priority=SuggestionPriority(suggestion['priority']), package=app)
def _fill_config_async(self, output: dict): def _fill_config_async(self, output: dict):
output.update(read_config()) output.update(self.configman.get_config())
def list_suggestions(self, limit: int, filter_installed: bool) -> List[PackageSuggestion]: def list_suggestions(self, limit: int, filter_installed: bool) -> List[PackageSuggestion]:
web_config = {} web_config = {}
@@ -903,14 +915,14 @@ class WebApplicationManager(SoftwareManager):
if self.suggestions: if self.suggestions:
suggestions = self.suggestions suggestions = self.suggestions
elif self.suggestions_downloader: elif self.suggestions_loader:
self.suggestions_downloader.join(5) self.suggestions_loader.join(5)
suggestions = self.suggestions suggestions = self.suggestions
else: else:
suggestions = SuggestionsDownloader(logger=self.logger, http_client=self.http_client, i18n=self.i18n).download() suggestions = SuggestionsManager(logger=self.logger, http_client=self.http_client, i18n=self.i18n).download()
# cleaning memory # cleaning memory
self.suggestions_downloader = None self.suggestions_loader = None
self.suggestions = None self.suggestions = None
if suggestions: if suggestions:
@@ -981,7 +993,7 @@ class WebApplicationManager(SoftwareManager):
traceback.print_exc() traceback.print_exc()
def get_settings(self, screen_width: int, screen_height: int) -> ViewComponent: def get_settings(self, screen_width: int, screen_height: int) -> ViewComponent:
web_config = read_config() web_config = self.configman.get_config()
max_width = floor(screen_width * 0.15) max_width = floor(screen_width * 0.15)
input_electron = TextInputComponent(label=self.i18n['web.settings.electron.version.label'], input_electron = TextInputComponent(label=self.i18n['web.settings.electron.version.label'],
@@ -1018,7 +1030,7 @@ class WebApplicationManager(SoftwareManager):
return PanelComponent([form_env]) return PanelComponent([form_env])
def save_settings(self, component: PanelComponent) -> Tuple[bool, Optional[List[str]]]: def save_settings(self, component: PanelComponent) -> Tuple[bool, Optional[List[str]]]:
web_config = read_config() web_config = self.configman.get_config()
form_env = component.components[0] form_env = component.components[0]
@@ -1036,7 +1048,7 @@ class WebApplicationManager(SoftwareManager):
web_config['environment']['cache_exp'] = form_env.get_component('web_cache_exp').get_int_value() web_config['environment']['cache_exp'] = form_env.get_component('web_cache_exp').get_int_value()
try: try:
save_config(web_config, CONFIG_FILE) self.configman.save_config(web_config)
return True, None return True, None
except: except:
return False, [traceback.format_exc()] return False, [traceback.format_exc()]

View File

@@ -41,12 +41,13 @@ class EnvironmentComponent:
class EnvironmentUpdater: class EnvironmentUpdater:
def __init__(self, logger: logging.Logger, http_client: HttpClient, file_downloader: FileDownloader, i18n: I18n): def __init__(self, logger: logging.Logger, http_client: HttpClient, file_downloader: FileDownloader, i18n: I18n, taskman: Optional[TaskManager] = None):
self.logger = logger self.logger = logger
self.file_downloader = file_downloader self.file_downloader = file_downloader
self.i18n = i18n self.i18n = i18n
self.http_client = http_client self.http_client = http_client
self.task_read_settings_id = 'web_read_settings' self.task_read_settings_id = 'web_read_settings'
self.taskman = taskman
def _download_and_install(self, version: str, version_url: str, watcher: ProcessWatcher) -> bool: def _download_and_install(self, version: str, version_url: str, watcher: ProcessWatcher) -> bool:
self.logger.info("Downloading NodeJS {}: {}".format(version, version_url)) self.logger.info("Downloading NodeJS {}: {}".format(version, version_url))
@@ -267,10 +268,10 @@ class EnvironmentUpdater:
return res return res
def _finish_task_download_settings(self, task_man: TaskManager): def _finish_task_download_settings(self):
if task_man: if self.taskman:
task_man.update_progress(self.task_read_settings_id, 100, None) self.taskman.update_progress(self.task_read_settings_id, 100, None)
task_man.finish_task(self.task_read_settings_id) self.taskman.finish_task(self.task_read_settings_id)
def should_download_settings(self, web_config: dict) -> bool: def should_download_settings(self, web_config: dict) -> bool:
try: try:
@@ -302,7 +303,14 @@ class EnvironmentUpdater:
self.logger.error("Could not parse environment settings file timestamp: {}".format(env_ts_str)) self.logger.error("Could not parse environment settings file timestamp: {}".format(env_ts_str))
return True return True
return env_timestamp + timedelta(minutes=settings_exp) <= datetime.utcnow() expired = env_timestamp + timedelta(minutes=settings_exp) <= datetime.utcnow()
if expired:
self.logger.info("Environment settings file has expired. It should be re-downloaded")
return True
else:
self.logger.info("Cached environment settings file is up to date")
return False
def read_cached_settings(self, web_config: dict) -> Optional[dict]: def read_cached_settings(self, web_config: dict) -> Optional[dict]:
if not self.should_download_settings(web_config): if not self.should_download_settings(web_config):
@@ -314,32 +322,33 @@ class EnvironmentUpdater:
except yaml.YAMLError: except yaml.YAMLError:
self.logger.error('Could not parse the cache environment settings file: {}'.format(cached_settings_str)) self.logger.error('Could not parse the cache environment settings file: {}'.format(cached_settings_str))
def register_task_read_settings(self, taskman: TaskManager): def read_settings(self, web_config: dict, cache: bool = True) -> Optional[dict]:
taskman.register_task(self.task_read_settings_id, self.i18n['web.task.download_settings'], get_icon_path()) if self.taskman:
self.taskman.register_task(self.task_read_settings_id, self.i18n['web.task.download_settings'], get_icon_path())
self.taskman.update_progress(self.task_read_settings_id, 1, None)
def read_settings(self, web_config: dict, cache: bool = True, taskman: Optional[TaskManager] = None) -> Optional[dict]:
cached_settings = self.read_cached_settings(web_config) if cache else None cached_settings = self.read_cached_settings(web_config) if cache else None
if cached_settings: if cached_settings:
return cached_settings return cached_settings
try: try:
if taskman: if self.taskman:
taskman.update_progress(self.task_read_settings_id, 10, None) self.taskman.update_progress(self.task_read_settings_id, 10, None)
self.logger.info("Downloading environment settings") self.logger.info("Downloading environment settings")
res = self.http_client.get(URL_ENVIRONMENT_SETTINGS) res = self.http_client.get(URL_ENVIRONMENT_SETTINGS)
if not res: if not res:
self.logger.warning('Could not retrieve the environments settings from the cloud') self.logger.warning('Could not retrieve the environments settings from the cloud')
self._finish_task_download_settings(taskman) self._finish_task_download_settings()
return return
try: try:
settings = yaml.safe_load(res.content) settings = yaml.safe_load(res.content)
except yaml.YAMLError: except yaml.YAMLError:
self.logger.error('Could not parse environment settings: {}'.format(res.text)) self.logger.error('Could not parse environment settings: {}'.format(res.text))
self._finish_task_download_settings(taskman) self._finish_task_download_settings()
return return
self.logger.info("Caching environment settings to disk") self.logger.info("Caching environment settings to disk")
@@ -350,7 +359,7 @@ class EnvironmentUpdater:
except OSError: except OSError:
self.logger.error("Could not create Web cache directory: {}".format(cache_dir)) self.logger.error("Could not create Web cache directory: {}".format(cache_dir))
self.logger.info('Finished') self.logger.info('Finished')
self._finish_task_download_settings(taskman) self._finish_task_download_settings()
return return
cache_timestamp = datetime.utcnow().timestamp() cache_timestamp = datetime.utcnow().timestamp()
@@ -360,12 +369,12 @@ class EnvironmentUpdater:
with open(ENVIRONMENT_SETTINGS_TS_FILE, 'w+') as f: with open(ENVIRONMENT_SETTINGS_TS_FILE, 'w+') as f:
f.write(str(cache_timestamp)) f.write(str(cache_timestamp))
self._finish_task_download_settings(taskman) self._finish_task_download_settings()
self.logger.info("Finished") self.logger.info("Finished")
return settings return settings
except requests.exceptions.ConnectionError: except requests.exceptions.ConnectionError:
self._finish_task_download_settings(taskman) self._finish_task_download_settings()
return return
def _check_and_fill_electron(self, pkg: WebApplication, env: dict, local_config: dict, x86_x64: bool, widevine: bool, output: List[EnvironmentComponent]): def _check_and_fill_electron(self, pkg: WebApplication, env: dict, local_config: dict, x86_x64: bool, widevine: bool, output: List[EnvironmentComponent]):

View File

@@ -73,7 +73,9 @@ web.settings.nativefier.system.tooltip=The Nativefier version installed on your
web.settings.nativefier.system=system web.settings.nativefier.system=system
web.settings.nativefier.tip=Defines which Nativefier version should be used to generate the Web applications web.settings.nativefier.tip=Defines which Nativefier version should be used to generate the Web applications
web.task.download_settings=Updating environment settings web.task.download_settings=Updating environment settings
web.task.suggestions=Downloading applications suggestions list web.task.search_index=Indexing suggestions
web.task.suggestions=Downloading suggestions
web.task.suggestions.saving=Saving to disk
web.uninstall.error.install_dir.not_found=The installation directory {} was not found web.uninstall.error.install_dir.not_found=The installation directory {} was not found
web.uninstall.error.remove_dir=It was not possible to remove {} web.uninstall.error.remove_dir=It was not possible to remove {}
web.waiting.env_updater=Updating environment web.waiting.env_updater=Updating environment

View File

@@ -73,7 +73,9 @@ web.settings.nativefier.system.tooltip=The Nativefier version installed on your
web.settings.nativefier.system=system web.settings.nativefier.system=system
web.settings.nativefier.tip=Defines which Nativefier version should be used to generate the Web applications web.settings.nativefier.tip=Defines which Nativefier version should be used to generate the Web applications
web.task.download_settings=Updating environment settings web.task.download_settings=Updating environment settings
web.task.suggestions=Downloading applications suggestions list web.task.search_index=Indexing suggestions
web.task.suggestions=Downloading suggestions
web.task.suggestions.saving=Saving to disk
web.uninstall.error.install_dir.not_found=The installation directory {} was not found web.uninstall.error.install_dir.not_found=The installation directory {} was not found
web.uninstall.error.remove_dir=It was not possible to remove {} web.uninstall.error.remove_dir=It was not possible to remove {}
web.waiting.env_updater=Updating environment web.waiting.env_updater=Updating environment

View File

@@ -73,7 +73,9 @@ web.settings.nativefier.system.tooltip=Se utilizará la versión de Nativefier i
web.settings.nativefier.system=sistema web.settings.nativefier.system=sistema
web.settings.nativefier.tip=Define qué versión de Nativefier debe usarse para generar las aplicaciones Web web.settings.nativefier.tip=Define qué versión de Nativefier debe usarse para generar las aplicaciones Web
web.task.download_settings=Actualizando configuraciones de ambiente web.task.download_settings=Actualizando configuraciones de ambiente
web.task.suggestions=Descargando la lista de sugerencias de aplicaciones web.task.search_index=Indexando sugerencias
web.task.suggestions=Descargando sugerencias
web.task.suggestions.saving=Guardando en disco
web.uninstall.error.install_dir.not_found=No se encontró el directorio de instalación {} web.uninstall.error.install_dir.not_found=No se encontró el directorio de instalación {}
web.uninstall.error.remove_dir=No fue posible eliminar {} web.uninstall.error.remove_dir=No fue posible eliminar {}
web.waiting.env_updater=Actualizando el ambiente web.waiting.env_updater=Actualizando el ambiente

View File

@@ -73,7 +73,9 @@ web.settings.nativefier.system.tooltip=La version de Nativefier installée sur v
web.settings.nativefier.system=système web.settings.nativefier.system=système
web.settings.nativefier.tip=Definit quelle version de Nativefier doit être utilisée pour géner les applications Web web.settings.nativefier.tip=Definit quelle version de Nativefier doit être utilisée pour géner les applications Web
web.task.download_settings=Mise à jour des paramètres d'environnement web.task.download_settings=Mise à jour des paramètres d'environnement
web.task.suggestions=Téléchargement de la liste de suggestions d'applications web.task.search_index=Indexing suggestions
web.task.suggestions=Téléchargement de suggestions
web.task.suggestions.saving=Saving to disk
web.uninstall.error.install_dir.not_found=Impossible de trouver le dossier d'installation {} web.uninstall.error.install_dir.not_found=Impossible de trouver le dossier d'installation {}
web.uninstall.error.remove_dir=Impossible d'enlever {} web.uninstall.error.remove_dir=Impossible d'enlever {}
web.waiting.env_updater=Mise à jour de l'environnement web.waiting.env_updater=Mise à jour de l'environnement

View File

@@ -73,7 +73,9 @@ web.settings.nativefier.system.tooltip=The Nativefier version installed on your
web.settings.nativefier.system=system web.settings.nativefier.system=system
web.settings.nativefier.tip=Defines which Nativefier version should be used to generate the Web applications web.settings.nativefier.tip=Defines which Nativefier version should be used to generate the Web applications
web.task.download_settings=Updating environment settings web.task.download_settings=Updating environment settings
web.task.suggestions=Downloading applications suggestions list web.task.search_index=Indexing suggestions
web.task.suggestions=Downloading suggestions
web.task.suggestions.saving=Saving to disk
web.uninstall.error.install_dir.not_found=The installation directory {} was not found web.uninstall.error.install_dir.not_found=The installation directory {} was not found
web.uninstall.error.remove_dir=It was not possible to remove {} web.uninstall.error.remove_dir=It was not possible to remove {}
web.waiting.env_updater=Updating environment web.waiting.env_updater=Updating environment

View File

@@ -72,7 +72,9 @@ web.settings.nativefier.system.tooltip=A versão do Nativefier instalada no seu
web.settings.nativefier.system=sistema web.settings.nativefier.system=sistema
web.settings.nativefier.tip=Define qual versão do Nativefier será utilizada para gerar os aplicativos Web web.settings.nativefier.tip=Define qual versão do Nativefier será utilizada para gerar os aplicativos Web
web.task.download_settings=Atualizando configurações de ambiente web.task.download_settings=Atualizando configurações de ambiente
web.task.suggestions=Baixando lista de sugestões de aplicativos web.task.search_index=Indexando sugestões
web.task.suggestions=Baixando sugestões
web.task.suggestions.saving=Salvando em disco
web.uninstall.error.install_dir.not_found=O diretório de instalação {} não foi encontrado web.uninstall.error.install_dir.not_found=O diretório de instalação {} não foi encontrado
web.uninstall.error.remove=Não foi possível remover {} web.uninstall.error.remove=Não foi possível remover {}
web.waiting.env_updater=Atualizando ambiente web.waiting.env_updater=Atualizando ambiente

View File

@@ -73,7 +73,9 @@ web.settings.nativefier.system=Из системы
web.settings.nativefier.system.tooltip=Будет использоваться версия Nativefier установленная в Вашей системе web.settings.nativefier.system.tooltip=Будет использоваться версия Nativefier установленная в Вашей системе
web.settings.nativefier.tip=Определяет, какие Nativefier версии должны быдут использованы для установки веб-приложений web.settings.nativefier.tip=Определяет, какие Nativefier версии должны быдут использованы для установки веб-приложений
web.task.download_settings=Updating environment settings web.task.download_settings=Updating environment settings
web.task.suggestions=Downloading applications suggestions list web.task.search_index=Indexing suggestions
web.task.suggestions=Downloading suggestions
web.task.suggestions.saving=Saving to disk
web.uninstall.error.install_dir.not_found=Каталог установки {} не найден web.uninstall.error.install_dir.not_found=Каталог установки {} не найден
web.uninstall.error.remove_dir=Не удалось удалить {} web.uninstall.error.remove_dir=Не удалось удалить {}
web.waiting.env_updater=Обнавляется Веб-среда web.waiting.env_updater=Обнавляется Веб-среда

View File

@@ -73,7 +73,9 @@ web.settings.nativefier.system.tooltip=Sisteminizde yüklü olan Nativefier sür
web.settings.nativefier.system=sistem web.settings.nativefier.system=sistem
web.settings.nativefier.tip=Web uygulamalarını oluşturmak için hangi Nativefier sürümünün kullanılması gerektiğini tanımlar web.settings.nativefier.tip=Web uygulamalarını oluşturmak için hangi Nativefier sürümünün kullanılması gerektiğini tanımlar
web.task.download_settings=Ortam ayarları güncelleniyor web.task.download_settings=Ortam ayarları güncelleniyor
web.task.suggestions=Uygulama öneri listesi indiriliyor web.task.search_index=Indexing suggestions
web.task.suggestions=Downloading suggestions
web.task.suggestions.saving=Saving to disk
web.uninstall.error.install_dir.not_found={} kurulum dizini bulunamadı web.uninstall.error.install_dir.not_found={} kurulum dizini bulunamadı
web.uninstall.error.remove_dir={} kaldırmak mümkün olmadı web.uninstall.error.remove_dir={} kaldırmak mümkün olmadı
web.waiting.env_updater=Ortam güncelleniyor web.waiting.env_updater=Ortam güncelleniyor

View File

@@ -0,0 +1,59 @@
import os
import traceback
from logging import Logger
from pathlib import Path
import requests
import yaml
from bauh.api.http import HttpClient
from bauh.gems.web import URL_SUGGESTIONS, SUGGESTIONS_CACHE_FILE
from bauh.view.util.translation import I18n
class SuggestionsManager:
def __init__(self, http_client: HttpClient, logger: Logger, i18n: I18n):
self.http_client = http_client
self.logger = logger
self.i18n = i18n
def download(self) -> dict:
self.logger.info("Reading suggestions from {}".format(URL_SUGGESTIONS))
try:
suggestions = self.http_client.get_yaml(URL_SUGGESTIONS, session=False)
if suggestions:
self.logger.info("{} suggestions successfully read".format(len(suggestions)))
else:
self.logger.warning("Could not read suggestions from {}".format(URL_SUGGESTIONS))
except (requests.exceptions.ConnectionError, requests.exceptions.ConnectTimeout):
self.logger.warning("Internet seems to be off: it was not possible to retrieve the suggestions")
suggestions = {}
self.logger.info("Finished")
return suggestions
def save_to_disk(self, suggestions: dict):
if not suggestions:
return
self.logger.info('Caching {} suggestions to the disk'.format(len(suggestions)))
suggestions_file_dir = os.path.dirname(SUGGESTIONS_CACHE_FILE)
try:
Path(suggestions_file_dir).mkdir(parents=True, exist_ok=True)
except OSError:
self.logger.error("Could not generate the directory {}".format(suggestions_file_dir))
traceback.print_exc()
return
try:
with open(SUGGESTIONS_CACHE_FILE, 'w+') as f:
f.write(yaml.safe_dump(suggestions))
self.logger.info("{} suggestions successfully cached to file '{}'".format(len(suggestions), SUGGESTIONS_CACHE_FILE))
except:
self.logger.error("Could write to {}".format(SUGGESTIONS_CACHE_FILE))
traceback.print_exc()
return

View File

@@ -1,87 +1,85 @@
import logging import logging
import time
import traceback import traceback
from pathlib import Path from threading import Thread
from typing import Optional
import requests
import yaml import yaml
from bauh.api.abstract.handler import TaskManager from bauh.api.abstract.handler import TaskManager
from bauh.api.http import HttpClient from bauh.commons.boot import CreateConfigFile
from bauh.gems.web import URL_SUGGESTIONS, TEMP_PATH, SEARCH_INDEX_FILE, SUGGESTIONS_CACHE_FILE, get_icon_path from bauh.commons.html import bold
from bauh.gems.web import SEARCH_INDEX_FILE, get_icon_path
from bauh.gems.web.environment import EnvironmentUpdater
from bauh.gems.web.suggestions import SuggestionsManager
from bauh.view.util.translation import I18n from bauh.view.util.translation import I18n
class SuggestionsDownloader: class SuggestionsLoader(Thread):
def __init__(self, http_client: HttpClient, logger: logging.Logger, i18n: I18n, taskman: TaskManager = None): def __init__(self, taskman: TaskManager, manager: SuggestionsManager,
super(SuggestionsDownloader, self).__init__() i18n: I18n, logger: logging.Logger, suggestions_callback, suggestions: Optional[dict] = None):
self.http_client = http_client super(SuggestionsLoader, self).__init__(daemon=True)
self.logger = logger
self.taskman = taskman self.taskman = taskman
self.i18n = i18n
self.task_id = 'web_sugs' self.task_id = 'web_sugs'
self._task_registered = False self.manager = manager
self._task_finished = False self.suggestions_callback = suggestions_callback
self.i18n = i18n
self.logger = logger
self.suggestions = suggestions
self.task_name = self.i18n['web.task.suggestions']
self.taskman.register_task(self.task_id, self.task_name, get_icon_path())
def _finish_task(self): def run(self):
if self.taskman: ti = time.time()
self.taskman.update_progress(self.task_id, 10, None)
try:
self.suggestions = self.manager.download()
if self.suggestions_callback:
self.suggestions_callback(self.suggestions)
if self.suggestions:
self.taskman.update_progress(self.task_id, 50, self.i18n['web.task.suggestions.saving'])
self.manager.save_to_disk(self.suggestions)
except:
self.logger.error("Unexpected exception")
traceback.print_exc()
finally:
self.taskman.update_progress(self.task_id, 100, None) self.taskman.update_progress(self.task_id, 100, None)
self.taskman.finish_task(self.task_id) self.taskman.finish_task(self.task_id)
self._task_finished = True tf = time.time()
self.logger.info("Finished") self.logger.info("Finished. Took {0:.2f} seconds".format(tf - ti))
def register_task(self):
if self.taskman and not self._task_registered and not self._task_finished:
self.taskman.register_task(self.task_id, self.i18n['web.task.suggestions'], get_icon_path())
self._task_registered = True
def download(self) -> dict:
if self.taskman:
self.taskman.update_progress(self.task_id, 10, None)
self.logger.info("Reading suggestions from {}".format(URL_SUGGESTIONS))
try:
suggestions = self.http_client.get_yaml(URL_SUGGESTIONS, session=False)
if suggestions:
self.logger.info("{} suggestions successfully read".format(len(suggestions)))
else:
self.logger.warning("Could not read suggestions from {}".format(URL_SUGGESTIONS))
except (requests.exceptions.ConnectionError, requests.exceptions.ConnectTimeout):
self.logger.warning("Internet seems to be off: it was not possible to retrieve the suggestions")
self._finish_task()
return {}
self._finish_task()
return suggestions
class SearchIndexGenerator: class SearchIndexGenerator(Thread):
def __init__(self, logger: logging.Logger): def __init__(self, taskman: TaskManager, suggestions_loader: SuggestionsLoader, i18n: I18n, logger: logging.Logger):
super(SearchIndexGenerator, self).__init__(daemon=True)
self.taskman = taskman
self.i18n = i18n
self.logger = logger self.logger = logger
self.suggestions_loader = suggestions_loader
self.task_id = 'web_idx_gen'
self.taskman.register_task(self.task_id, self.i18n['web.task.search_index'], get_icon_path())
def run(self):
ti = time.time()
self.taskman.update_progress(self.task_id, 0, self.i18n['task.waiting_task'].format(bold(self.suggestions_loader.task_name)))
self.suggestions_loader.join()
if self.suggestions_loader.suggestions:
self.generate_index(self.suggestions_loader.suggestions)
else:
self.taskman.update_progress(self.task_id, 100, None)
self.taskman.finish_task(self.task_id)
tf = time.time()
self.logger.info("Finished. Took {0:.2f} seconds".format(tf - ti))
def generate_index(self, suggestions: dict): def generate_index(self, suggestions: dict):
self.logger.info('Caching {} suggestions to the disk'.format(len(suggestions))) self.taskman.update_progress(self.task_id, 1, None)
try:
Path(TEMP_PATH).mkdir(parents=True, exist_ok=True)
except:
self.logger.error("Could not generate the directory {}".format(TEMP_PATH))
traceback.print_exc()
return
try:
with open(SUGGESTIONS_CACHE_FILE, 'w+') as f:
f.write(yaml.safe_dump(suggestions))
self.logger.info('{} successfully cached to the disk as {}'.format(len(suggestions), SUGGESTIONS_CACHE_FILE))
except:
self.logger.error("Could write to {}".format(SUGGESTIONS_CACHE_FILE))
traceback.print_exc()
return
self.logger.info('Indexing suggestions') self.logger.info('Indexing suggestions')
index = {} index = {}
@@ -102,6 +100,7 @@ class SearchIndexGenerator:
mapped.add(key) mapped.add(key)
if index: if index:
self.taskman.update_progress(self.task_id, 50, self.i18n['web.task.suggestions.saving'])
self.logger.info('Preparing search index for writing') self.logger.info('Preparing search index for writing')
for key in index.keys(): for key in index.keys():
@@ -115,3 +114,29 @@ class SearchIndexGenerator:
except: except:
self.logger.error("Could not write the seach index to {}".format(SEARCH_INDEX_FILE)) self.logger.error("Could not write the seach index to {}".format(SEARCH_INDEX_FILE))
traceback.print_exc() traceback.print_exc()
self.taskman.update_progress(self.task_id, 100, None)
self.taskman.finish_task(self.task_id)
class UpdateEnvironmentSettings(Thread):
def __init__(self, env_updater: EnvironmentUpdater, taskman: TaskManager, i18n: I18n, create_config: CreateConfigFile):
super(UpdateEnvironmentSettings, self).__init__(daemon=True)
self.env_updater = env_updater
self.taskman = taskman
self.create_config = create_config
self.task_id = env_updater.task_read_settings_id
self.i18n = i18n
def run(self):
self.taskman.register_task(self.task_id, self.i18n['web.task.download_settings'], get_icon_path())
self.taskman.update_progress(self.task_id, 1, self.i18n['task.waiting_task'].format(bold(self.create_config.task_name)))
self.create_config.join()
web_config = self.create_config.config
if self.env_updater.should_download_settings(web_config):
self.env_updater.read_settings(web_config=web_config, cache=False)
else:
self.taskman.update_progress(self.task_id, 100, None)
self.taskman.finish_task(self.task_id)

View File

@@ -1,80 +1,73 @@
from pathlib import Path from pathlib import Path
import yaml
from bauh import __app_name__ from bauh import __app_name__
from bauh.commons.config import read_config as read from bauh.commons.config import YAMLConfigManager
CONFIG_PATH = '{}/.config/{}'.format(Path.home(), __app_name__) FILE_PATH = '{}/.config/{}/config.yml'.format(str(Path.home()), __app_name__)
FILE_PATH = '{}/config.yml'.format(CONFIG_PATH)
def read_config(update_file: bool = False) -> dict: class CoreConfigManager(YAMLConfigManager):
default = {
'gems': None, def __init__(self):
'memory_cache': { super(CoreConfigManager, self).__init__(config_file_path=FILE_PATH)
'data_expiration': 60 * 60,
'icon_expiration': 60 * 5 def get_default_config(self) -> dict:
}, return {
'locale': None, 'gems': None,
'updates': { 'memory_cache': {
'check_interval': 30, 'data_expiration': 60 * 60,
'ask_for_reboot': True 'icon_expiration': 60 * 5
},
'system': {
'notifications': True,
'single_dependency_checking': False
},
'suggestions': {
'enabled': True,
'by_type': 10
},
'ui': {
'table': {
'max_displayed': 50
}, },
'tray': { 'locale': None,
'default_icon': None, 'updates': {
'updates_icon': None 'check_interval': 30,
'ask_for_reboot': True
}, },
'qt_style': 'fusion', 'system': {
'hdpi': True, 'notifications': True,
"auto_scale": False, 'single_dependency_checking': False
"scale_factor": 1.0, },
'theme': 'light', 'suggestions': {
'system_theme': False 'enabled': True,
'by_type': 10
},
'ui': {
'table': {
'max_displayed': 50
},
'tray': {
'default_icon': None,
'updates_icon': None
},
'qt_style': 'fusion',
'hdpi': True,
"auto_scale": False,
"scale_factor": 1.0,
'theme': 'light',
'system_theme': False
}, },
'download': { 'download': {
'multithreaded': True, 'multithreaded': True,
'multithreaded_client': None, 'multithreaded_client': None,
'icons': True 'icons': True
}, },
'store_root_password': True, 'store_root_password': True,
'disk': { 'disk': {
'trim': { 'trim': {
'after_upgrade': False 'after_upgrade': False
}
},
'backup': {
'enabled': True,
'install': None,
'uninstall': None,
'downgrade': None,
'upgrade': None,
'mode': 'incremental',
'type': 'rsync'
},
'boot': {
'load_apps': True
} }
},
'backup': {
'enabled': True,
'install': None,
'uninstall': None,
'downgrade': None,
'upgrade': None,
'mode': 'incremental',
'type': 'rsync'
},
'boot': {
'load_apps': True
} }
}
return read(FILE_PATH, default, update_file=update_file, update_async=True)
def save(config: dict):
Path(CONFIG_PATH).mkdir(parents=True, exist_ok=True)
with open(FILE_PATH, 'w+') as f:
f.write(yaml.safe_dump(config))

View File

@@ -14,12 +14,14 @@ from bauh.api.abstract.model import SoftwarePackage, PackageUpdate, PackageHisto
CustomSoftwareAction CustomSoftwareAction
from bauh.api.abstract.view import ViewComponent, TabGroupComponent, MessageType from bauh.api.abstract.view import ViewComponent, TabGroupComponent, MessageType
from bauh.api.exception import NoInternetException from bauh.api.exception import NoInternetException
from bauh.commons.boot import CreateConfigFile
from bauh.commons.html import bold from bauh.commons.html import bold
from bauh.commons.system import run_cmd from bauh.commons.system import run_cmd
from bauh.view.core.config import read_config from bauh.view.core.config import CoreConfigManager
from bauh.view.core.settings import GenericSettingsManager from bauh.view.core.settings import GenericSettingsManager
from bauh.view.core.update import check_for_update from bauh.view.core.update import check_for_update
from bauh.view.util import resource from bauh.view.util import resource
from bauh.view.util.resource import get_path
from bauh.view.util.util import clean_app_files, restart_app from bauh.view.util.util import clean_app_files, restart_app
RE_IS_URL = re.compile(r'^https?://.+') RE_IS_URL = re.compile(r'^https?://.+')
@@ -52,6 +54,7 @@ class GenericSoftwareManager(SoftwareManager):
self.config = config self.config = config
self.settings_manager = settings_manager self.settings_manager = settings_manager
self.http_client = context.http_client self.http_client = context.http_client
self.configman = CoreConfigManager()
self.extra_actions = [CustomSoftwareAction(i18n_label_key='action.reset', self.extra_actions = [CustomSoftwareAction(i18n_label_key='action.reset',
i18n_status_key='action.reset.status', i18n_status_key='action.reset.status',
manager_method='reset', manager_method='reset',
@@ -402,14 +405,25 @@ class GenericSoftwareManager(SoftwareManager):
def prepare(self, task_manager: TaskManager, root_password: str, internet_available: bool): def prepare(self, task_manager: TaskManager, root_password: str, internet_available: bool):
ti = time.time() ti = time.time()
self.logger.info("Initializing") self.logger.info("Initializing")
taskman = task_manager if task_manager else TaskManager() # empty task manager to prevent null pointers
create_config = CreateConfigFile(taskman=taskman, configman=self.configman, i18n=self.i18n,
task_icon_path=get_path('img/logo.svg'), logger=self.logger)
create_config.start()
if self.managers: if self.managers:
internet_on = self.context.is_internet_available() internet_on = self.context.is_internet_available()
taskman = task_manager if task_manager else TaskManager() # empty task manager to prevent null pointers prepare_tasks = []
for man in self.managers: for man in self.managers:
if man not in self._already_prepared and self._can_work(man): if man not in self._already_prepared and self._can_work(man):
man.prepare(taskman, root_password, internet_on) t = Thread(target=man.prepare, args=(taskman, root_password, internet_on), daemon=True)
t.start()
prepare_tasks.append(t)
self._already_prepared.append(man) self._already_prepared.append(man)
for t in prepare_tasks:
t.join()
tf = time.time() tf = time.time()
self.logger.info("Finished. Took {0:.2f} seconds".format(tf - ti)) self.logger.info("Finished. Took {0:.2f} seconds".format(tf - ti))
@@ -525,7 +539,8 @@ class GenericSoftwareManager(SoftwareManager):
working_managers=self.working_managers, working_managers=self.working_managers,
logger=self.logger, logger=self.logger,
i18n=self.i18n, i18n=self.i18n,
file_downloader=self.context.file_downloader) file_downloader=self.context.file_downloader,
configman=self.configman)
else: else:
self.settings_manager.managers = self.managers self.settings_manager.managers = self.managers
self.settings_manager.working_managers = self.working_managers self.settings_manager.working_managers = self.working_managers
@@ -618,7 +633,7 @@ class GenericSoftwareManager(SoftwareManager):
if man_actions: if man_actions:
actions.extend(man_actions) actions.extend(man_actions)
app_config = read_config() app_config = self.configman.get_config()
for action, available in self.dynamic_extra_actions.items(): for action, available in self.dynamic_extra_actions.items():
if available(app_config): if available(app_config):

View File

@@ -13,8 +13,8 @@ from bauh.api.abstract.view import ViewComponent, TabComponent, InputOption, Tex
PanelComponent, FormComponent, TabGroupComponent, SingleSelectComponent, SelectViewType, TextInputComponent, \ PanelComponent, FormComponent, TabGroupComponent, SingleSelectComponent, SelectViewType, TextInputComponent, \
FileChooserComponent, RangeInputComponent FileChooserComponent, RangeInputComponent
from bauh.commons.view_utils import new_select from bauh.commons.view_utils import new_select
from bauh.view.core import config, timeshift from bauh.view.core import timeshift
from bauh.view.core.config import read_config from bauh.view.core.config import CoreConfigManager
from bauh.view.core.downloader import AdaptableFileDownloader from bauh.view.core.downloader import AdaptableFileDownloader
from bauh.view.util import translation from bauh.view.util import translation
from bauh.view.util.translation import I18n from bauh.view.util.translation import I18n
@@ -23,12 +23,13 @@ from bauh.view.util.translation import I18n
class GenericSettingsManager: class GenericSettingsManager:
def __init__(self, managers: List[SoftwareManager], working_managers: List[SoftwareManager], def __init__(self, managers: List[SoftwareManager], working_managers: List[SoftwareManager],
logger: logging.Logger, i18n: I18n, file_downloader: FileDownloader): logger: logging.Logger, i18n: I18n, file_downloader: FileDownloader, configman: CoreConfigManager):
self.i18n = i18n self.i18n = i18n
self.managers = managers self.managers = managers
self.working_managers = working_managers self.working_managers = working_managers
self.logger = logger self.logger = logger
self.file_downloader = file_downloader self.file_downloader = file_downloader
self.configman = configman
def get_settings(self, screen_width: int, screen_height: int) -> ViewComponent: def get_settings(self, screen_width: int, screen_height: int) -> ViewComponent:
tabs = list() tabs = list()
@@ -54,7 +55,7 @@ class GenericSettingsManager:
if man.is_enabled() and man in self.working_managers: if man.is_enabled() and man in self.working_managers:
def_gem_opts.add(opt) def_gem_opts.add(opt)
core_config = read_config() core_config = self.configman.get_config()
if gem_opts: if gem_opts:
type_help = TextComponent(html=self.i18n['core.config.types.tip']) type_help = TextComponent(html=self.i18n['core.config.types.tip'])
@@ -340,7 +341,7 @@ class GenericSettingsManager:
ui: PanelComponent, ui: PanelComponent,
tray: PanelComponent, tray: PanelComponent,
gems_panel: PanelComponent) -> Tuple[bool, Optional[List[str]]]: gems_panel: PanelComponent) -> Tuple[bool, Optional[List[str]]]:
core_config = config.read_config() core_config = self.configman.get_config()
# general # general
general_form = general.components[0] general_form = general.components[0]
@@ -443,7 +444,7 @@ class GenericSettingsManager:
core_config['gems'] = None if core_config['gems'] is None and len(checked_gems) == len(self.managers) else checked_gems core_config['gems'] = None if core_config['gems'] is None and len(checked_gems) == len(self.managers) else checked_gems
try: try:
config.save(core_config) self.configman.save_config(core_config)
return True, None return True, None
except: except:
return False, [traceback.format_exc()] return False, [traceback.format_exc()]

View File

@@ -1,6 +1,8 @@
import datetime import datetime
import operator import operator
import time
from functools import reduce from functools import reduce
from threading import Lock
from typing import Tuple, Optional from typing import Tuple, Optional
from PyQt5.QtCore import QSize, Qt, QThread, pyqtSignal, QCoreApplication from PyQt5.QtCore import QSize, Qt, QThread, pyqtSignal, QCoreApplication
@@ -34,7 +36,10 @@ class Prepare(QThread, TaskManager):
self.context = context self.context = context
self.waiting_password = False self.waiting_password = False
self.password_response = None self.password_response = None
self._registered = 0 self._tasks_added = set()
self._tasks_finished = set()
self._add_lock = Lock()
self._finish_lock = Lock()
def ask_password(self) -> Tuple[bool, Optional[str]]: def ask_password(self) -> Tuple[bool, Optional[str]]:
self.waiting_password = True self.waiting_password = True
@@ -58,20 +63,42 @@ class Prepare(QThread, TaskManager):
QCoreApplication.exit(1) QCoreApplication.exit(1)
self.manager.prepare(self, root_pwd, None) self.manager.prepare(self, root_pwd, None)
self.signal_started.emit(self._registered) self._add_lock.acquire()
self.signal_started.emit(len(self._tasks_added))
self._add_lock.release()
def update_progress(self, task_id: str, progress: float, substatus: str): def update_progress(self, task_id: str, progress: float, substatus: str):
self.signal_update.emit(task_id, progress, substatus) if task_id in self._tasks_added:
self.signal_update.emit(task_id, progress, substatus)
def update_output(self, task_id: str, output: str): def update_output(self, task_id: str, output: str):
self.signal_output.emit(task_id, output) if task_id in self._tasks_added:
self.signal_output.emit(task_id, output)
def register_task(self, id_: str, label: str, icon_path: str): def register_task(self, id_: str, label: str, icon_path: str):
self._registered += 1 self._add_lock.acquire()
self.signal_register.emit(id_, label, icon_path)
if id_ not in self._tasks_added:
self._tasks_added.add(id_)
self.signal_register.emit(id_, label, icon_path)
self._add_lock.release()
def finish_task(self, task_id: str): def finish_task(self, task_id: str):
self.signal_finished.emit(task_id) self._add_lock.acquire()
task_registered = task_id in self._tasks_added
self._add_lock.release()
if not task_registered:
return
self._finish_lock.acquire()
if task_id not in self._tasks_finished:
self._tasks_finished.add(task_id)
self.signal_finished.emit(task_id)
self._finish_lock.release()
class CheckFinished(QThread): class CheckFinished(QThread):
@@ -84,7 +111,7 @@ class CheckFinished(QThread):
def run(self): def run(self):
while True: while True:
if self.total == self.finished: if self.finished == self.total:
break break
self.msleep(5) self.msleep(5)
@@ -134,6 +161,7 @@ class PreparePanel(QWidget, TaskManager):
self.output = {} self.output = {}
self.added_tasks = 0 self.added_tasks = 0
self.ftasks = 0 self.ftasks = 0
self.started_at = None
self.self_close = False self.self_close = False
self.prepare_thread = Prepare(self.context, manager, self.i18n) self.prepare_thread = Prepare(self.context, manager, self.i18n)
@@ -263,6 +291,7 @@ class PreparePanel(QWidget, TaskManager):
centralize(self) centralize(self)
def start(self, tasks: int): def start(self, tasks: int):
self.started_at = time.time()
self.check_thread.total = tasks self.check_thread.total = tasks
self.check_thread.start() self.check_thread.start()
self.skip_thread.start() self.skip_thread.start()
@@ -387,9 +416,8 @@ class PreparePanel(QWidget, TaskManager):
def finish_task(self, task_id: str): def finish_task(self, task_id: str):
task = self.tasks[task_id] task = self.tasks[task_id]
task['lb_sub'].setText('')
for key in ('lb_prog', 'lb_status'): for key in ('lb_prog', 'lb_status', 'lb_sub'):
label = task[key] label = task[key]
label.setProperty('status', 'done') label.setProperty('status', 'done')
label.style().unpolish(label) label.style().unpolish(label)
@@ -402,10 +430,9 @@ class PreparePanel(QWidget, TaskManager):
self.ftasks += 1 self.ftasks += 1
self.signal_status.emit(self.ftasks) self.signal_status.emit(self.ftasks)
if self.table.rowCount() == self.ftasks:
self.label_top.setText(self.i18n['ready'].capitalize())
def finish(self): def finish(self):
now = time.time()
self.context.logger.info("{0} tasks finished in {1:.9f} seconds".format(self.ftasks, (now - self.started_at)))
if self.isVisible(): if self.isVisible():
self.manage_window.show() self.manage_window.show()

View File

@@ -9,7 +9,7 @@ from PyQt5.QtWidgets import QLineEdit, QApplication, QDialog, QPushButton, QVBox
from bauh.api.abstract.context import ApplicationContext from bauh.api.abstract.context import ApplicationContext
from bauh.commons.system import new_subprocess from bauh.commons.system import new_subprocess
from bauh.view.core.config import read_config from bauh.view.core.config import CoreConfigManager
from bauh.view.qt.components import QtComponentsManager, new_spacer from bauh.view.qt.components import QtComponentsManager, new_spacer
from bauh.view.util import util from bauh.view.util import util
from bauh.view.util.translation import I18n from bauh.view.util.translation import I18n
@@ -131,7 +131,7 @@ class RootDialog(QDialog):
def ask_password(context: ApplicationContext, i18n: I18n, app_config: Optional[dict] = None, def ask_password(context: ApplicationContext, i18n: I18n, app_config: Optional[dict] = None,
comp_manager: Optional[QtComponentsManager] = None, tries: int = 3) -> Tuple[bool, Optional[str]]: comp_manager: Optional[QtComponentsManager] = None, tries: int = 3) -> Tuple[bool, Optional[str]]:
current_config = read_config() if not app_config else app_config current_config = CoreConfigManager().get_config() if not app_config else app_config
store_password = bool(current_config['store_root_password']) store_password = bool(current_config['store_root_password'])

View File

@@ -23,8 +23,8 @@ from bauh.api.exception import NoInternetException
from bauh.commons import user from bauh.commons import user
from bauh.commons.html import bold from bauh.commons.html import bold
from bauh.commons.system import get_human_size_str, ProcessHandler, SimpleProcess from bauh.commons.system import get_human_size_str, ProcessHandler, SimpleProcess
from bauh.view.core import timeshift, config from bauh.view.core import timeshift
from bauh.view.core.config import read_config from bauh.view.core.config import CoreConfigManager
from bauh.view.qt import commons from bauh.view.qt import commons
from bauh.view.qt.view_model import PackageView, PackageViewStatus from bauh.view.qt.view_model import PackageView, PackageViewStatus
from bauh.view.util.translation import I18n from bauh.view.util.translation import I18n
@@ -466,7 +466,7 @@ class UpgradeSelected(AsyncAction):
self.change_substatus('') self.change_substatus('')
app_config = read_config() app_config = CoreConfigManager().get_config()
# backup dialog ( if enabled, supported and accepted ) # backup dialog ( if enabled, supported and accepted )
should_backup = bkp_supported should_backup = bkp_supported
@@ -572,7 +572,7 @@ class UninstallPackage(AsyncAction):
pkg=self.pkg, pkg=self.pkg,
i18n=self.i18n, i18n=self.i18n,
root_password=self.root_pwd, root_password=self.root_pwd,
app_config=read_config()) app_config=CoreConfigManager().get_config())
if not proceed: if not proceed:
self.notify_finished({'success': False, 'removed': None, 'pkg': self.pkg}) self.notify_finished({'success': False, 'removed': None, 'pkg': self.pkg})
self.pkg = None self.pkg = None
@@ -615,7 +615,7 @@ class DowngradePackage(AsyncAction):
pkg=self.pkg, pkg=self.pkg,
i18n=self.i18n, i18n=self.i18n,
root_password=self.root_pwd, root_password=self.root_pwd,
app_config=read_config()) app_config=CoreConfigManager().get_config())
if not proceed: if not proceed:
self.notify_finished({'app': self.pkg, 'success': success}) self.notify_finished({'app': self.pkg, 'success': success})
@@ -707,7 +707,7 @@ class InstallPackage(AsyncAction):
pkg=self.pkg, pkg=self.pkg,
i18n=self.i18n, i18n=self.i18n,
root_password=self.root_pwd, root_password=self.root_pwd,
app_config=read_config()) app_config=CoreConfigManager().get_config())
if not proceed: if not proceed:
self.signal_finished.emit(res) self.signal_finished.emit(res)
@@ -1007,7 +1007,7 @@ class CustomAction(AsyncAction):
res = {'success': False, 'pkg': self.pkg, 'action': self.custom_action, 'error': None, 'error_type': MessageType.ERROR} res = {'success': False, 'pkg': self.pkg, 'action': self.custom_action, 'error': None, 'error_type': MessageType.ERROR}
if self.custom_action.backup: if self.custom_action.backup:
proceed, _ = self.request_backup(app_config=read_config(), proceed, _ = self.request_backup(app_config=CoreConfigManager.get_config(),
action_key=None, action_key=None,
i18n=self.i18n, i18n=self.i18n,
root_password=self.root_pwd, root_password=self.root_pwd,
@@ -1081,10 +1081,11 @@ class SaveTheme(QThread):
def run(self): def run(self):
if self.theme_key: if self.theme_key:
core_config = read_config() configman = CoreConfigManager()
core_config = configman.get_config()
core_config['ui']['theme'] = self.theme_key core_config['ui']['theme'] = self.theme_key
try: try:
config.save(core_config) configman.save_config(core_config)
except: except:
traceback.print_exc() traceback.print_exc()

View File

@@ -22,7 +22,7 @@ from bauh.commons import user
from bauh.commons.html import bold from bauh.commons.html import bold
from bauh.context import set_theme from bauh.context import set_theme
from bauh.stylesheet import read_all_themes_metadata, ThemeMetadata from bauh.stylesheet import read_all_themes_metadata, ThemeMetadata
from bauh.view.core.config import read_config from bauh.view.core.config import CoreConfigManager
from bauh.view.core.tray_client import notify_tray from bauh.view.core.tray_client import notify_tray
from bauh.view.qt import dialog, commons, qt_utils from bauh.view.qt import dialog, commons, qt_utils
from bauh.view.qt.about import AboutDialog from bauh.view.qt.about import AboutDialog
@@ -1586,7 +1586,7 @@ class ManageWindow(QWidget):
menu_row.exec_() menu_row.exec_()
def _map_theme_actions(self, menu: QMenu) -> List[QCustomMenuAction]: def _map_theme_actions(self, menu: QMenu) -> List[QCustomMenuAction]:
core_config = read_config() core_config = CoreConfigManager().get_config()
current_theme_key, current_action = core_config['ui']['theme'], None current_theme_key, current_action = core_config['ui']['theme'], None

View File

@@ -391,6 +391,8 @@ status.caching_data=Sestan emmagatzemant {} dades a la memòria cau al disc
style=estil style=estil
success=success success=success
summary=resum summary=resum
task.checking_config=Checking configuration file
task.checking_config.saving=Creating file
task.download_categories=Download de categories task.download_categories=Download de categories
task.waiting_task=Waiting for {} task.waiting_task=Waiting for {}
type=tipus type=tipus

View File

@@ -391,6 +391,8 @@ status.caching_data={} Daten auf der Festplatte zwischenspeichern
style=Stil style=Stil
success=success success=success
summary=Zusammenfassung summary=Zusammenfassung
task.checking_config=Checking configuration file
task.checking_config.saving=Creating file
task.download_categories=Downloading categories task.download_categories=Downloading categories
task.waiting_task=Waiting for {} task.waiting_task=Waiting for {}
type=Typ type=Typ

View File

@@ -392,6 +392,8 @@ status.caching_data=Caching {} data to disk
style=style style=style
success=success success=success
summary=summary summary=summary
task.checking_config=Checking configuration file
task.checking_config.saving=Creating file
task.download_categories=Downloading categories task.download_categories=Downloading categories
task.waiting_task=Waiting for {} task.waiting_task=Waiting for {}
type=type type=type

View File

@@ -394,6 +394,8 @@ status.caching_data=Almacenando en antememoria los datos de {} para el disco
style=estilo style=estilo
success=éxito success=éxito
summary=resumen summary=resumen
task.checking_config=Verificando archivo de configuración
task.checking_config.saving=Creando archivo
task.download_categories=Descargando categorías task.download_categories=Descargando categorías
task.waiting_task=Esperando por {} task.waiting_task=Esperando por {}
type=tipo type=tipo

View File

@@ -388,6 +388,8 @@ status.caching_data=Mise en cache des données de {} sur disque
style=style style=style
success=succès success=succès
summary=résumé summary=résumé
task.checking_config=Checking configuration file
task.checking_config.saving=Creating file
task.download_categories=Téléchargement des catégories task.download_categories=Téléchargement des catégories
task.waiting_task=Waiting for {} task.waiting_task=Waiting for {}
type=type type=type

View File

@@ -394,6 +394,8 @@ status.caching_data=Memorizza {} dati sul disco
style=stile style=stile
success=success success=success
summary=riepilogo summary=riepilogo
task.checking_config=Checking configuration file
task.checking_config.saving=Creating file
task.download_categories=Download delle categorie task.download_categories=Download delle categorie
task.waiting_task=Waiting for {} task.waiting_task=Waiting for {}
type=tipe type=tipe

View File

@@ -392,6 +392,8 @@ status.caching_data=Cacheando dados de {} para o disco
style=estilo style=estilo
success=sucesso success=sucesso
summary=resumo summary=resumo
task.checking_config=Verificando arquivo de configuração
task.checking_config.saving=Criando arquivo
task.download_categories=Baixando categorias task.download_categories=Baixando categorias
task.waiting_task=Aguardando {} task.waiting_task=Aguardando {}
type=tipo type=tipo

View File

@@ -391,6 +391,8 @@ status.caching_data=Кэширование данных {} на диск
style=Стиль style=Стиль
success=success success=success
summary=Суммарно summary=Суммарно
task.checking_config=Checking configuration file
task.checking_config.saving=Creating file
task.download_categories=Downloading categories task.download_categories=Downloading categories
task.waiting_task=Waiting for {} task.waiting_task=Waiting for {}
type=Тип type=Тип

View File

@@ -391,6 +391,8 @@ status.caching_data={} verilerini diske önbellekle
style=Görünüm biçimi style=Görünüm biçimi
success=başarılı success=başarılı
summary=özet summary=özet
task.checking_config=Checking configuration file
task.checking_config.saving=Creating file
task.download_categories=Kategoriler indiriliyor task.download_categories=Kategoriler indiriliyor
task.waiting_task=Waiting for {} task.waiting_task=Waiting for {}
type=tür type=tür

View File

@@ -238,7 +238,7 @@ PreparePanel QTableWidget#tasks {
background-color: @inner_widget.background.color; background-color: @inner_widget.background.color;
} }
PreparePanel QLabel#task_status[status = "done"], QLabel#task_progress[status = "done"] { PreparePanel QLabel#task_status[status = "done"], PreparePanel QLabel#task_progress[status = "done"], PreparePanel QLabel#task_substatus[status = "done"] {
color: @task.done.color; color: @task.done.color;
} }

View File

@@ -219,7 +219,7 @@ PreparePanel QPushButton#bt_hide_details {
background: none; background: none;
} }
PreparePanel QLabel#task_status[status = "done"], QLabel#task_progress[status = "done"] { PreparePanel QLabel#task_status[status = "done"], PreparePanel QLabel#task_progress[status = "done"], PreparePanel QLabel#task_substatus[status = "done"] {
text-decoration: line-through; text-decoration: line-through;
} }

View File

@@ -145,11 +145,11 @@ PreparePanel QTableWidget#tasks {
background-color: @task.background.color; background-color: @task.background.color;
} }
PreparePanel QLabel#task_status[status = "running"], QLabel#task_progress[status = "running"] { PreparePanel QLabel#task_status[status = "running"], PreparePanel QLabel#task_progress[status = "running"] {
font-weight: 525; font-weight: 525;
} }
PreparePanel QLabel#task_status[status = "done"], QLabel#task_progress[status = "done"] { PreparePanel QLabel#task_status[status = "done"], PreparePanel QLabel#task_progress[status = "done"], PreparePanel QLabel#task_substatus[status = "done"] {
color: @task.done.color; color: @task.done.color;
} }

View File

@@ -195,7 +195,7 @@ PreparePanel QLabel#task_status[status = "running"], QLabel#task_progress[status
color: @task.running.color; color: @task.running.color;
} }
PreparePanel QLabel#task_status[status = "done"], QLabel#task_progress[status = "done"] { PreparePanel QLabel#task_status[status = "done"], PreparePanel QLabel#task_progress[status = "done"], PreparePanel QLabel#task_substatus[status = "done"]{
color: @task.done.color; color: @task.done.color;
} }