[config] new general config file

This commit is contained in:
Vinícius Moreira
2019-12-19 19:39:17 -03:00
parent ef6175172a
commit b819b1ec82
12 changed files with 148 additions and 129 deletions

View File

@@ -12,6 +12,36 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- requires only **python-beautifulsoup4** and **python-lxml** to be enabled
### Improvements
- configuration file **~/.config/bauh/config.json** renamed to **~/.config/bauh/config.yml**
- some parameters were moved to the configuration file ( **~/.config/bauh/config.yml** ):
- `--cache-exp` and `--icon-exp` became:
```cache:
data_expiration:
icon_expiration:
```
- `--locale`
- `--check-interval` became:
```
updates:
check_interval:
```
- `--system-notifications` -> `system_notifications`
- `--disk-cache`
- `--download-icons`
- `--check-packaging-once`
- `--sugs` ( renamed as `suggestions` )
- `--max-displayed`
- `--download-mthread`
- some settings from **~/.config/bauh/config.json** were renamed in **~/.config/bauh/config.yml**:
- `enabled_gems` -> `gems`
- some environment variables were moved as fields in **~/.config/bauh/config.yml**:
- `BAUH_TRAY_DEFAULT_ICON_PATH` and `BAUH_TRAY_UPDATES_ICON_PATH` became:
```
tray:
icon_default: null, # path to the icon representing the default state
icon_updates: null # path to the icon representing the "new updates" state
```
- AppImage:
- cleaning the downloaded database files when **--reset** is passed as parameter
- environment variables **BAUH_APPIMAGE_DB_UPDATER** and **BAUH_APPIMAGE_DB_UPDATER_TIME** dropped in favor of the new configuration file located at **~/.config/bauh/appimage.yml**

View File

@@ -183,19 +183,8 @@ environment:
### General settings
You can change some application settings via environment variables or arguments (type ```bauh --help``` to get more information).
- **BAUH_SYSTEM_NOTIFICATIONS**: enable or disable system notifications. Use **0** (disable) or **1** (enable, default).
- **BAUH_CHECK_INTERVAL**: define the updates check interval in seconds. Default: 60.
- **BAUH_LOCALE**: define a custom app translation for a given locale key (e.g: 'pt', 'en', 'es', ...). Default: system locale.
- **BAUH_CACHE_EXPIRATION**: define a custom expiration time in SECONDS for cached API data. Default: 3600 (1 hour).
- **BAUH_ICON_EXPIRATION**: define a custom expiration time in SECONDS for cached icons. Default: 300 (5 minutes).
- **BAUH_DISK_CACHE**: enables / disables disk cache. When disk cache is enabled, the installed packages data are loaded faster. Use **0** (disable) or **1** (enable, default).
- **BAUH_DOWNLOAD_ICONS**: Enables / disables applications icons downloading. It may improve the application speed depending on how applications data are being retrieved. Use **0** (disable) or **1** (enable, default).
- **BAUH_CHECK_PACKAGING_ONCE**: If the availabilty of the supported packaging types should be checked only once. It improves the application speed if enabled, but can generate errors if you uninstall any packaging technology while using it, and every time a new supported packaging type is installed it will only be available after a restart. Use **0** (disable, default) or **1** (enable).
- **BAUH_TRAY**: If the tray icon and update-check daemon should be created. Use **0** (disable, default) or **1** (enable).
- **BAUH_SUGGESTIONS**: If application suggestions should be displayed if no package considered an application is installed (runtimes / libraries do not count as applications). Use **0** (disable) or **1** (enable, default).
- **BAUH_MAX_DISPLAYED**: Maximum number of displayed packages in the management panel table. Default: 50.
- **BAUH_LOGS**: enable **bauh** logs (for debugging purposes). Use: **0** (disable, default) or **1** (enable)
- **BAUH_DOWNLOAD_MULTITHREAD**: enable multi-threaded download for installation files ( only possible if **aria2** is installed ). This feature reduces the application installation time. Use **0** (disable) or **1** (enabled, default).
- **BAUH_TRAY_DEFAULT_ICON_PATH**: define a custom icon for the tray mode ( absolute path)
- **BAUH_TRAY_UPDATES_ICON_PATH** define a custom updates icon for the tray mode ( absolute path)

View File

@@ -1,5 +1,6 @@
import os
import sys
from threading import Thread
import urllib3
from PyQt5.QtGui import QIcon
@@ -32,36 +33,38 @@ def main():
logger = logs.new_logger(__app_name__, bool(args.logs))
app_args.validate(args, logger)
i18n_key, current_i18n = translation.get_locale_keys(args.locale)
local_config = config.read_config(update_file=True)
config.validate(local_config, logger)
i18n_key, current_i18n = translation.get_locale_keys(local_config.locale)
default_i18n = translation.get_locale_keys(DEFAULT_I18N_KEY)[1] if i18n_key != DEFAULT_I18N_KEY else {}
i18n = I18n(i18n_key, current_i18n, DEFAULT_I18N_KEY, default_i18n)
cache_cleaner = CacheCleaner()
cache_factory = DefaultMemoryCacheFactory(expiration_time=args.cache_exp, cleaner=cache_cleaner)
icon_cache = cache_factory.new(args.icon_exp)
cache_factory = DefaultMemoryCacheFactory(expiration_time=local_config.cache_exp, cleaner=cache_cleaner)
icon_cache = cache_factory.new(local_config.icon_exp)
http_client = HttpClient(logger)
context = ApplicationContext(i18n=i18n,
http_client=http_client,
disk_cache=args.disk_cache,
download_icons=args.download_icons,
disk_cache=local_config.disk_cache,
download_icons=local_config.download_icons,
app_root_dir=ROOT_DIR,
cache_factory=cache_factory,
disk_loader_factory=DefaultDiskCacheLoaderFactory(disk_cache_enabled=args.disk_cache, logger=logger),
disk_loader_factory=DefaultDiskCacheLoaderFactory(disk_cache_enabled=local_config.disk_cache, logger=logger),
logger=logger,
distro=util.get_distro(),
file_downloader=AdaptableFileDownloader(logger, bool(args.download_mthread),
file_downloader=AdaptableFileDownloader(logger, local_config.download_mthread,
i18n, http_client))
user_config = config.read()
managers = gems.load_managers(context=context, locale=i18n_key, config=user_config, default_locale=DEFAULT_I18N_KEY)
managers = gems.load_managers(context=context, locale=i18n_key, config=local_config, default_locale=DEFAULT_I18N_KEY)
if args.reset:
util.clean_app_files(managers)
exit(0)
manager = GenericSoftwareManager(managers, context=context, app_args=args)
manager = GenericSoftwareManager(managers, context=context, config=local_config)
manager.prepare()
app = QApplication(sys.argv)
@@ -69,8 +72,8 @@ def main():
app.setApplicationVersion(__version__)
app.setWindowIcon(QIcon(resource.get_path('img/logo.svg')))
if user_config.style:
app.setStyle(user_config.style)
if local_config.style:
app.setStyle(local_config.style)
else:
if app.style().objectName().lower() not in {'fusion', 'breeze'}:
app.setStyle('Fusion')
@@ -78,23 +81,18 @@ def main():
manage_window = ManageWindow(i18n=i18n,
manager=manager,
icon_cache=icon_cache,
disk_cache=args.disk_cache,
download_icons=bool(args.download_icons),
screen_size=app.primaryScreen().size(),
suggestions=args.sugs,
display_limit=args.max_displayed,
config=user_config,
config=local_config,
context=context,
http_client=http_client,
logger=logger,
notifications=bool(args.system_notifications))
logger=logger)
if args.tray:
tray_icon = TrayIcon(i18n=i18n,
manager=manager,
manage_window=manage_window,
check_interval=args.check_interval,
update_notification=bool(args.system_notifications))
check_interval=local_config.update_check_interval,
update_notification=local_config.system_notifications)
manage_window.set_tray_icon(tray_icon)
tray_icon.show()
@@ -105,6 +103,7 @@ def main():
manage_window.show()
cache_cleaner.start()
Thread(target=config.remove_old_config, args=(logger,), daemon=True).start()
sys.exit(app.exec_())

View File

@@ -9,69 +9,17 @@ from bauh import __app_name__, __version__
def read() -> Namespace:
parser = argparse.ArgumentParser(prog=__app_name__, description="GUI for Linux package management")
parser.add_argument('-v', '--version', action='version', version='%(prog)s {}'.format(__version__))
parser.add_argument('-e', '--cache-exp', action="store",
default=int(os.getenv('BAUH_CACHE_EXPIRATION', 60 * 60)), type=int,
help='default memory caches expiration time in SECONDS. Default: %(default)s')
parser.add_argument('-ie', '--icon-exp', action="store", default=int(os.getenv('BAUH_ICON_EXPIRATION', 60 * 5)),
type=int, help='cached icons expiration time in SECONDS. Default: %(default)s')
parser.add_argument('-l', '--locale', action="store", default=os.getenv('BAUH_LOCALE'), help='Locale key. e.g: en, es, pt, ...')
parser.add_argument('-i', '--check-interval', action="store", default=int(os.getenv('BAUH_CHECK_INTERVAL', 60)),
type=int, help='Updates check interval in SECONDS. Default: %(default)s')
parser.add_argument('-n', '--system-notifications', action="store", choices=[0, 1],
default=os.getenv('BAUH_SYSTEM_NOTIFICATIONS', 1), type=int,
help='Enables / disables system notifications. Default: %(default)s')
parser.add_argument('-dc', '--disk-cache', action="store", choices=[0, 1],
default=os.getenv('BAUH_DISK_CACHE', 1), type=int,
help='Enables / disables disk cache. When disk cache is enabled, the installed applications data are loaded faster. Default: %(default)s')
parser.add_argument('-di', '--download-icons', action="store", choices=[0, 1],
default=os.getenv('BAUH_DOWNLOAD_ICONS', 1), type=int,
help='Enables / disables package icons download. It may improve the application speed, depending of how applications data are retrieved by their extensions.')
parser.add_argument('-co', '--check-packaging-once', action="store",
default=os.getenv('BAUH_CHECK_PACKAGING_ONCE', 0), choices=[0, 1], type=int,
help='If the available supported packaging types should be checked ONLY once. It improves the application speed if enabled, but can generate errors if you uninstall any packaging technology while using it, and every time a supported packaging type is installed it will only be available after a restart. Default: %(default)s')
parser.add_argument('--tray', action="store", default=os.getenv('BAUH_TRAY', 0), choices=[0, 1], type=int,
help='If the tray icon and update-check daemon should be created. Default: %(default)s')
parser.add_argument('--sugs', action="store", default=os.getenv('BAUH_SUGGESTIONS', 1), choices=[0, 1], type=int, help='If app suggestions should be displayed if no application package is installed (runtimes / libraries do not count as apps). Default: %(default)s')
parser.add_argument('-md', '--max-displayed', action="store", default=os.getenv('BAUH_MAX_DISPLAYED', 50), type=int, help='Maximum number of displayed packages in the management panel table. Default: %(default)s')
parser.add_argument('--logs', action="store", default=int(os.getenv('BAUH_LOGS', 0)), choices=[0, 1], type=int, help='If the application logs should be displayed. Default: %(default)s')
parser.add_argument('--show-panel', action="store_true", help='Shows the management panel after the app icon is attached to the tray.')
parser.add_argument('-dmt', '--download-mthread', action="store", default=os.getenv('BAUH_DOWNLOAD_MULTITHREAD', 1), choices=[0, 1], type=int, help='If installation files should be downloaded using multi-threads (only possible if aria2c is installed). Not all gems support this feature. Check README.md. Default: %(default)s')
parser.add_argument('--reset', action="store_true", help='Removes all configuration and cache files')
return parser.parse_args()
def validate(args: Namespace, logger: logging.Logger):
if args.cache_exp < 0:
logger.info("'cache-exp' set to '{}': cache will not expire.".format(args.cache_exp))
if args.icon_exp < 0:
logger.info("'icon-exp' set to '{}': cache will not expire.".format(args.cache_exp))
if args.locale and not args.locale.strip():
logger.info("'locale' set as '{}'. You must provide a valid one. Aborting...".format(args.locale))
exit(1)
if args.check_interval <= 0:
logger.info("'check-interval' set as '{}'. It must be >= 0. Aborting...".format(args.check_interval))
exit(1)
if args.system_notifications == 0:
logger.info('system notifications are disabled')
if args.download_icons == 0:
logger.info("'download-icons' is disabled")
if args.check_packaging_once == 1:
logger.info("'check-packaging-once' is enabled")
if args.sugs == 0:
logger.info("suggestions are disabled")
if args.logs == 1:
logger.info("Logs are enabled")
if args.download_mthread == 1:
logger.info("Multi-threaded downloads enabled")
return args

View File

@@ -1,5 +1,6 @@
import os
from pathlib import Path
from threading import Thread
import yaml
@@ -7,13 +8,10 @@ from bauh.api.constants import CONFIG_PATH
from bauh.commons import util
def read_config(file_path: str, template: dict, update_file: bool = False) -> dict:
def read_config(file_path: str, template: dict, update_file: bool = False, update_async: bool = False) -> dict:
if not os.path.exists(file_path):
Path(CONFIG_PATH).mkdir(parents=True, exist_ok=True)
with open(file_path, 'w+') as f:
f.write(yaml.dump(template))
save_config(template, file_path)
else:
with open(file_path) as f:
local_config = yaml.safe_load(f.read())
@@ -22,7 +20,14 @@ def read_config(file_path: str, template: dict, update_file: bool = False) -> di
util.deep_update(template, local_config)
if update_file:
with open(file_path, 'w+') as f:
f.write(yaml.dump(template))
if update_async:
Thread(target=save_config, args=(template, file_path), daemon=True).start()
else:
save_config(template, file_path)
return template
def save_config(config: dict, file_path: str):
with open(file_path, 'w+') as f:
f.write(yaml.dump(config))

View File

@@ -399,7 +399,7 @@ class AppImageManager(SoftwareManager):
updater.download_databases() # only once
def prepare(self):
Thread(target=self._start_updater()).start()
Thread(target=self._start_updater, daemon=True).start()
def list_updates(self, internet_available: bool) -> List[PackageUpdate]:
res = self.read_installed(disk_loader=None, internet_available=internet_available)

View File

@@ -706,13 +706,13 @@ class WebApplicationManager(SoftwareManager):
if self.suggestions:
index_gen = SearchIndexGenerator(logger=self.logger)
Thread(target=index_gen.generate_index, args=(self.suggestions,)).start()
Thread(target=index_gen.generate_index, args=(self.suggestions,), daemon=True).start()
def prepare(self):
self.env_thread = Thread(target=self._update_env_settings())
self.env_thread = Thread(target=self._update_env_settings, daemon=True)
self.env_thread.start()
self.suggestions_downloader = Thread(target=self._download_suggestions)
self.suggestions_downloader = Thread(target=self._download_suggestions, daemon=True)
self.suggestions_downloader.start()
def list_updates(self, internet_available: bool) -> List[PackageUpdate]:
@@ -761,7 +761,7 @@ class WebApplicationManager(SoftwareManager):
app.status = PackageStatus.LOADING_DATA
Thread(target=self._fill_suggestion, args=(app,)).start()
Thread(target=self._fill_suggestion, args=(app,), daemon=True).start()
return PackageSuggestion(priority=SuggestionPriority(suggestion['priority']), package=app)

View File

@@ -1,34 +1,86 @@
import json
import logging
import os
import traceback
from pathlib import Path
from typing import List
from bauh import __app_name__
from bauh.api.constants import HOME_PATH
import yaml
CONFIG_PATH = '{}/.config/{}'.format(HOME_PATH, __app_name__)
FILE_PATH = '{}/config.json'.format(CONFIG_PATH)
from bauh import __app_name__
from bauh.commons.config import read_config as read
CONFIG_PATH = '{}/.config/{}'.format(Path.home(), __app_name__)
FILE_PATH = '{}/config.yml'.format(CONFIG_PATH)
# TODO stopped here
class UpdatesSettings:
def __init__(self, check_interval: int, **kwargs):
self.check_interval = check_interval
class CacheSettings:
def __init__(self, data_expiration: int, icon_expiration: int, **kwargs):
self.data_expiration = data_expiration
self.icon_expiration = icon_expiration
class Configuration:
def __init__(self, enabled_gems: List[str] = None, style: str = None):
self.enabled_gems = enabled_gems
def __init__(self, gems: List[str], style: str, cache: dict, locale: str,
updates: dict, system_notifications: bool, disk_cache: bool, download_icons: bool,
check_packaging_once: bool, suggestions: bool, max_displayed: int, download_mthread: bool,
**kwargs):
self.gems = gems
self.style = style
self.cache = CacheSettings(**cache)
self.locale = locale
self.updates = UpdatesSettings(**updates)
self.system_notifications = system_notifications
self.disk_cache = disk_cache
self.download_icons = download_icons
self.check_packaging_once = check_packaging_once
self.suggestions = suggestions
self.max_displayed = max_displayed
self.download_mthread = download_mthread
def read() -> Configuration:
if os.path.exists(FILE_PATH):
with open(FILE_PATH) as f:
config_file = f.read()
return Configuration(**json.loads(config_file))
return Configuration()
def read_config(update_file: bool = False) -> Configuration:
default = {
'gems': None,
'style': None,
'cache_exp': 60 * 60,
'icon_exp': 60 * 5,
'locale': None,
'updates': {
'check_interval': 60
},
'system_notifications': True,
'disk_cache': True,
'download_icons': True,
'check_packaging_once': False,
'suggestions': True,
'max_displayed': 50, # table
'download_mthread': True # downloads
}
obj = read(FILE_PATH, default, update_file=update_file, update_async=True)
return Configuration(**obj)
def save(config: Configuration):
Path(CONFIG_PATH).mkdir(parents=True, exist_ok=True)
with open(FILE_PATH, 'w+') as f:
f.write(json.dumps(config.__dict__, indent=2))
f.write(yaml.safe_dump(config.__dict__))
def remove_old_config(logger: logging.Logger):
old_file = FILE_PATH.replace('.yml', '.json')
if os.path.exists(old_file):
try:
os.remove(old_file)
logger.info('Old configuration file {} deleted'.format(old_file))
except:
logger.error('Could not delete the old configuration file {}'.format(old_file))
traceback.print_exc()

View File

@@ -11,6 +11,7 @@ from bauh.api.abstract.handler import ProcessWatcher
from bauh.api.abstract.model import SoftwarePackage, PackageUpdate, PackageHistory, PackageSuggestion, PackageAction
from bauh.api.exception import NoInternetException
from bauh.commons import internet
from bauh.view.core.config import Configuration
RE_IS_URL = re.compile(r'^https?://.+')
@@ -19,11 +20,11 @@ SUGGESTIONS_LIMIT = 10
class GenericSoftwareManager(SoftwareManager):
def __init__(self, managers: List[SoftwareManager], context: ApplicationContext, app_args: Namespace):
def __init__(self, managers: List[SoftwareManager], context: ApplicationContext, config: Configuration):
super(GenericSoftwareManager, self).__init__(context=context)
self.managers = managers
self.map = {t: m for m in self.managers for t in m.get_managed_types()}
self._available_cache = {} if app_args.check_packaging_once else None
self._available_cache = {} if config.check_packaging_once else None
self.thread_prepare = None
self.i18n = context.i18n
self.disk_loader_factory = context.disk_loader_factory

View File

@@ -44,10 +44,10 @@ def load_managers(locale: str, context: ApplicationContext, config: Configuratio
man = manager_class(context=context)
if config.enabled_gems is None:
if config.gems is None:
man.set_enabled(man.is_default_enabled())
else:
man.set_enabled(f.name in config.enabled_gems)
man.set_enabled(f.name in config.gems)
managers.append(man)

View File

@@ -34,7 +34,7 @@ class StylesComboBox(QComboBox):
self.last_index = idx
style = self.styles[idx]
user_config = config.read()
user_config = config.read_config()
user_config.style = style
config.save(user_config)

View File

@@ -51,10 +51,8 @@ class ManageWindow(QWidget):
signal_user_res = pyqtSignal(bool)
signal_table_update = pyqtSignal()
def __init__(self, i18n: I18n, icon_cache: MemoryCache, manager: SoftwareManager, disk_cache: bool,
download_icons: bool, screen_size, suggestions: bool, display_limit: int, config: Configuration,
context: ApplicationContext, notifications: bool, http_client: HttpClient, logger: logging.Logger,
tray_icon=None):
def __init__(self, i18n: I18n, icon_cache: MemoryCache, manager: SoftwareManager, screen_size, config: Configuration,
context: ApplicationContext, http_client: HttpClient, logger: logging.Logger, tray_icon=None):
super(ManageWindow, self).__init__()
self.i18n = i18n
self.logger = logger
@@ -64,14 +62,11 @@ class ManageWindow(QWidget):
self.pkgs = [] # packages current loaded in the table
self.pkgs_available = [] # all packages loaded in memory
self.pkgs_installed = [] # cached installed packages
self.display_limit = display_limit
self.display_limit = config.max_displayed
self.icon_cache = icon_cache
self.disk_cache = disk_cache
self.download_icons = download_icons
self.screen_size = screen_size
self.config = config
self.context = context
self.notifications = notifications
self.http_client = http_client
self.icon_app = QIcon(resource.get_path('img/logo.svg'))
@@ -213,7 +208,7 @@ class ManageWindow(QWidget):
self.layout.addWidget(self.toolbar)
self.table_apps = AppsTable(self, self.icon_cache, disk_cache=self.disk_cache, download_icons=self.download_icons)
self.table_apps = AppsTable(self, self.icon_cache, disk_cache=self.config.disk_cache, download_icons=self.config.download_icons)
self.table_apps.change_headers_policy()
self.layout.addWidget(self.table_apps)
@@ -265,7 +260,7 @@ class ManageWindow(QWidget):
self.thread_apply_filters.signal_table.connect(self._update_table_and_upgrades)
self.signal_table_update.connect(self.thread_apply_filters.stop_waiting)
self.thread_install = InstallPackage(manager=self.manager, disk_cache=self.disk_cache, icon_cache=self.icon_cache, i18n=self.i18n)
self.thread_install = InstallPackage(manager=self.manager, disk_cache=self.config.disk_cache, icon_cache=self.icon_cache, i18n=self.i18n)
self._bind_async_action(self.thread_install, finished_call=self._finish_install)
self.thread_animate_progress = AnimateProgress()
@@ -313,7 +308,7 @@ class ManageWindow(QWidget):
self.types_changed = False
self.dialog_about = None
self.first_refresh = suggestions
self.first_refresh = config.suggestions
self.thread_warnings = ListWarnings(man=manager, i18n=i18n)
self.thread_warnings.signal_warnings.connect(self._show_warnings)
@@ -545,7 +540,7 @@ class ManageWindow(QWidget):
self.checkbox_console.setChecked(True)
def _can_notify_user(self):
return self.notifications and (self.isHidden() or self.isMinimized())
return self.config.system_notifications and (self.isHidden() or self.isMinimized())
def _finish_downgrade(self, res: dict):
self.finish_action()