refreshing only the needed package types

This commit is contained in:
Vinicius Moreira
2019-08-29 18:39:41 -03:00
parent 6b40232a05
commit fd6ec1f79f
6 changed files with 216 additions and 46 deletions

View File

@@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [0.6.0]
### Improvements:
### Fixes:
## [0.5.1] - 2019-08-12 ## [0.5.1] - 2019-08-12
### Improvements: ### Improvements:
- suggestions are now retrieved asynchronously taking 45% less time. - suggestions are now retrieved asynchronously taking 45% less time.

View File

@@ -1,6 +1,6 @@
from argparse import Namespace from argparse import Namespace
from threading import Thread from threading import Thread
from typing import List, Set from typing import List, Set, Type
from bauh_api.abstract.controller import SoftwareManager, SearchResult from bauh_api.abstract.controller import SoftwareManager, SearchResult
from bauh_api.abstract.handler import ProcessWatcher from bauh_api.abstract.handler import ProcessWatcher
@@ -96,20 +96,34 @@ class GenericSoftwareManager(SoftwareManager):
self.thread_prepare.join() self.thread_prepare.join()
self.thread_prepare = None self.thread_prepare = None
def read_installed(self, disk_loader: DiskCacheLoader = None) -> List[SoftwarePackage]: def read_installed(self, disk_loader: DiskCacheLoader = None, pkg_types: Set[Type[SoftwarePackage]] = None) -> List[SoftwarePackage]:
self._wait_to_be_ready() self._wait_to_be_ready()
installed = [] installed = []
disk_loader = None disk_loader = None
for man in self.managers: if not pkg_types: # any type
if self._is_enabled(man): for man in self.managers:
if not disk_loader: if self._is_enabled(man):
disk_loader = self.disk_loader_factory.new() if not disk_loader:
disk_loader.start() disk_loader = self.disk_loader_factory.new()
disk_loader.start()
installed.extend(man.read_installed(disk_loader=disk_loader)) installed.extend(man.read_installed(disk_loader=disk_loader, pkg_types=None))
else:
man_already_used = []
for t in pkg_types:
man = self.map.get(t)
if man and (man not in man_already_used) and self._is_enabled(man):
if not disk_loader:
disk_loader = self.disk_loader_factory.new()
disk_loader.start()
installed.extend(man.read_installed(disk_loader=disk_loader, pkg_types=None))
if disk_loader: if disk_loader:
disk_loader.stop = True disk_loader.stop = True

128
bauh/resources/img/disc.svg Executable file
View File

@@ -0,0 +1,128 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="Capa_1"
x="0px"
y="0px"
viewBox="0 0 24 24"
xml:space="preserve"
sodipodi:docname="disc_2.svg"
width="24"
height="24"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
inkscape:export-filename="/home/vinicius.moreira/shared_vb/disk_2.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"><metadata
id="metadata858"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs856">
</defs><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1366"
inkscape:window-height="739"
id="namedview854"
showgrid="false"
showborder="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="4.5416668"
inkscape:cx="55.143096"
inkscape:cy="1.6145437"
inkscape:window-x="0"
inkscape:window-y="432"
inkscape:window-maximized="1"
inkscape:current-layer="Capa_1" />
<g
id="g823"
transform="translate(-8.9954491,-22.380699)">
</g>
<g
id="g825"
transform="translate(-8.9954491,-22.380699)">
</g>
<g
id="g827"
transform="translate(-8.9954491,-22.380699)">
</g>
<g
id="g829"
transform="translate(-8.9954491,-22.380699)">
</g>
<g
id="g831"
transform="translate(-8.9954491,-22.380699)">
</g>
<g
id="g833"
transform="translate(-8.9954491,-22.380699)">
</g>
<g
id="g835"
transform="translate(-8.9954491,-22.380699)">
</g>
<g
id="g837"
transform="translate(-8.9954491,-22.380699)">
</g>
<g
id="g839"
transform="translate(-8.9954491,-22.380699)">
</g>
<g
id="g841"
transform="translate(-8.9954491,-22.380699)">
</g>
<g
id="g843"
transform="translate(-8.9954491,-22.380699)">
</g>
<g
id="g845"
transform="translate(-8.9954491,-22.380699)">
</g>
<g
id="g847"
transform="translate(-8.9954491,-22.380699)">
</g>
<g
id="g849"
transform="translate(-8.9954491,-22.380699)">
</g>
<g
id="g851"
transform="translate(-8.9954491,-22.380699)">
</g>
<g
id="g1005"><path
id="path920"
d="M 12 0.27929688 A 11.720572 11.720572 0 0 0 0.27929688 12 A 11.720572 11.720572 0 0 0 12 23.720703 A 11.720572 11.720572 0 0 0 23.720703 12 A 11.720572 11.720572 0 0 0 12 0.27929688 z M 12 8.59375 A 3.4069197 3.4069195 0 0 1 15.40625 12 A 3.4069197 3.4069195 0 0 1 12 15.40625 A 3.4069197 3.4069195 0 0 1 8.59375 12 A 3.4069197 3.4069195 0 0 1 12 8.59375 z "
style="fill:#ffffff;stroke:#cccccc;stroke-width:0.558855;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.94117647" /><ellipse
cy="12"
cx="12"
id="ellipse998"
style="fill:none;fill-opacity:0;stroke:#b3b3b3;stroke-width:0.558855;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.94117647"
rx="3.4069197"
ry="3.4069195" /></g></svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -239,19 +239,19 @@ class AppsTable(QTableWidget):
self.setEnabled(True) self.setEnabled(True)
if pkg_views: if pkg_views:
for idx, app_v in enumerate(pkg_views): for idx, pkgv in enumerate(pkg_views):
self._set_col_name(idx, app_v) self._set_col_name(idx, pkgv)
self._set_col_version(idx, app_v) self._set_col_version(idx, pkgv)
self._set_col_description(idx, app_v) self._set_col_description(idx, pkgv)
self._set_col_type(idx, app_v) self._set_col_type(idx, pkgv)
self._set_col_installed(idx, app_v) self._set_col_installed(idx, pkgv)
self._set_col_settings(idx, app_v) self._set_col_settings(idx, pkgv)
col_update = None col_update = None
if update_check_enabled and app_v.model.update: if update_check_enabled and pkgv.model.update:
col_update = UpdateToggleButton(app_v, self.window, self.window.locale_keys, app_v.model.update) col_update = UpdateToggleButton(pkgv, self.window, self.window.locale_keys, pkgv.model.update)
self.setCellWidget(idx, 6, col_update) self.setCellWidget(idx, 6, col_update)

View File

@@ -1,13 +1,13 @@
import subprocess import subprocess
import time import time
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import List from typing import List, Type, Set
import requests import requests
from PyQt5.QtCore import QThread, pyqtSignal from PyQt5.QtCore import QThread, pyqtSignal
from bauh_api.abstract.controller import SoftwareManager from bauh_api.abstract.controller import SoftwareManager
from bauh_api.abstract.handler import ProcessWatcher from bauh_api.abstract.handler import ProcessWatcher
from bauh_api.abstract.model import PackageStatus from bauh_api.abstract.model import PackageStatus, SoftwarePackage
from bauh_api.abstract.view import InputViewComponent, MessageType from bauh_api.abstract.view import InputViewComponent, MessageType
from bauh_api.exception import NoInternetException from bauh_api.exception import NoInternetException
from bauh_api.util.cache import Cache from bauh_api.util.cache import Cache
@@ -74,7 +74,7 @@ class UpdateSelectedApps(AsyncAction):
success = False success = False
if self.apps_to_update: if self.apps_to_update:
updated = 0 updated, updated_types = 0, set()
for app in self.apps_to_update: for app in self.apps_to_update:
self.change_status('{} {}...'.format(self.locale_keys['manage_window.status.upgrading'], app.model.base_data.name)) self.change_status('{} {}...'.format(self.locale_keys['manage_window.status.upgrading'], app.model.base_data.name))
success = bool(self.manager.update(app.model, self.root_password, self)) success = bool(self.manager.update(app.model, self.root_password, self))
@@ -83,37 +83,44 @@ class UpdateSelectedApps(AsyncAction):
break break
else: else:
updated += 1 updated += 1
updated_types.add(app.model.__class__)
self.signal_output.emit('\n') self.signal_output.emit('\n')
self.notify_finished({'success': success, 'updated': updated}) self.notify_finished({'success': success, 'updated': updated, 'types': updated_types})
self.apps_to_update = None self.apps_to_update = None
class RefreshApps(AsyncAction): class RefreshApps(AsyncAction):
def __init__(self, manager: SoftwareManager, app: PackageView = None): def __init__(self, manager: SoftwareManager, app: PackageView = None, pkg_types: Set[Type[SoftwarePackage]] = None):
super(RefreshApps, self).__init__() super(RefreshApps, self).__init__()
self.manager = manager self.manager = manager
self.app = app # app that should be on list top self.app = app # app that should be on list top
self.pkg_types = pkg_types
def run(self): def run(self):
installed = self.manager.read_installed() installed = self.manager.read_installed(pkg_types=self.pkg_types)
refreshed_types = set()
if installed and self.app: if installed:
idx_found, app_found = None, None idx_found, app_found = None, None
for idx, ins in enumerate(installed): for idx, ins in enumerate(installed):
if ins.get_type() == self.app.model.get_type() and ins.base_data.id == self.app.model.base_data.id: if self.app and ins.get_type() == self.app.model.get_type() and ins.base_data.id == self.app.model.base_data.id:
idx_found = idx idx_found = idx
app_found = ins app_found = ins
break break
if self.pkg_types:
refreshed_types.add(ins.__class__)
if app_found: if app_found:
del installed[idx_found] del installed[idx_found]
installed.insert(0, app_found) installed.insert(0, app_found)
self.notify_finished(installed) self.notify_finished({'installed': installed, 'types': refreshed_types})
self.app = None self.app = None
self.pkg_types = None
class UninstallApp(AsyncAction): class UninstallApp(AsyncAction):

View File

@@ -1,6 +1,6 @@
import operator import operator
from functools import reduce from functools import reduce
from typing import List from typing import List, Type, Set
from PyQt5.QtCore import QEvent, Qt, QSize, pyqtSignal from PyQt5.QtCore import QEvent, Qt, QSize, pyqtSignal
from PyQt5.QtGui import QIcon, QWindowStateChangeEvent, QPixmap from PyQt5.QtGui import QIcon, QWindowStateChangeEvent, QPixmap
@@ -273,6 +273,7 @@ class ManageWindow(QWidget):
self.ref_checkbox_only_apps.setVisible(True) self.ref_checkbox_only_apps.setVisible(True)
self.ref_bt_upgrade.setVisible(True) self.ref_bt_upgrade.setVisible(True)
self.update_apps(apps=None, as_installed=True) self.update_apps(apps=None, as_installed=True)
self.input_search.setText('')
def _show_about(self): def _show_about(self):
if self.dialog_about is None: if self.dialog_about is None:
@@ -324,7 +325,7 @@ class ManageWindow(QWidget):
self.checkbox_console.setChecked(False) self.checkbox_console.setChecked(False)
self.textarea_output.hide() self.textarea_output.hide()
def refresh_apps(self, keep_console: bool = True, top_app: PackageView = None): def refresh_apps(self, keep_console: bool = True, top_app: PackageView = None, pkg_types: Set[Type[SoftwarePackage]] = None):
self.type_filter = None self.type_filter = None
self.input_search.clear() self.input_search.clear()
@@ -335,16 +336,15 @@ class ManageWindow(QWidget):
self.ref_checkbox_only_apps.setVisible(False) self.ref_checkbox_only_apps.setVisible(False)
self._begin_action(self.locale_keys['manage_window.status.refreshing'], clear_filters=True) self._begin_action(self.locale_keys['manage_window.status.refreshing'], clear_filters=True)
if top_app: self.thread_refresh.app = top_app # the app will be on top when refresh happens
self.thread_refresh.app = top_app # the app will be on top when refresh happens self.thread_refresh.pkg_types = pkg_types
self.thread_refresh.start() self.thread_refresh.start()
def _finish_refresh_apps(self, apps: List[SoftwarePackage]): def _finish_refresh_apps(self, res: dict):
self.finish_action() self.finish_action()
self.ref_checkbox_only_apps.setVisible(True) self.ref_checkbox_only_apps.setVisible(True)
self.ref_bt_upgrade.setVisible(True) self.ref_bt_upgrade.setVisible(True)
self.update_apps(apps, as_installed=True) self.update_apps(res['installed'], as_installed=True, types=res['types'])
self.first_refresh = False self.first_refresh = False
def uninstall_app(self, app: PackageView): def uninstall_app(self, app: PackageView):
@@ -393,7 +393,7 @@ class ManageWindow(QWidget):
if self._can_notify_user(): if self._can_notify_user():
util.notify_user('{} ({}) {}'.format(app.model.base_data.name, app.model.get_type(), self.locale_keys['uninstalled'])) util.notify_user('{} ({}) {}'.format(app.model.base_data.name, app.model.get_type(), self.locale_keys['uninstalled']))
self.refresh_apps() self.refresh_apps(pkg_types={app.model.__class__})
else: else:
if self._can_notify_user(): if self._can_notify_user():
util.notify_user('{}: {}'.format(app.model.base_data.name, self.locale_keys['notification.uninstall.failed'])) util.notify_user('{}: {}'.format(app.model.base_data.name, self.locale_keys['notification.uninstall.failed']))
@@ -410,7 +410,7 @@ class ManageWindow(QWidget):
if self._can_notify_user(): if self._can_notify_user():
util.notify_user('{} {}'.format(res['app'], self.locale_keys['downgraded'])) util.notify_user('{} {}'.format(res['app'], self.locale_keys['downgraded']))
self.refresh_apps() self.refresh_apps(pkg_types={res['app'].model.__class__})
if self.tray_icon: if self.tray_icon:
self.tray_icon.verify_updates(notify_user=False) self.tray_icon.verify_updates(notify_user=False)
@@ -514,13 +514,19 @@ class ManageWindow(QWidget):
geo.moveCenter(center_point) geo.moveCenter(center_point)
self.move(geo.topLeft()) self.move(geo.topLeft())
def update_apps(self, apps: List[SoftwarePackage], as_installed: bool, update_check_enabled: bool = True): def update_apps(self, apps: List[SoftwarePackage], as_installed: bool, update_check_enabled: bool = True, types: Set[type] = None):
napps = 0 # number of apps (not libraries, runtimes or something else) napps = 0 # number of apps (not libraries, runtimes or something else)
available_types = {} available_types = {}
if apps is not None: if apps is not None:
self.pkgs = [] self.pkgs = []
old_installed = None
if as_installed:
old_installed = self.pkgs_installed
self.pkgs_installed = []
for app in apps: for app in apps:
app_model = PackageView(model=app, visible=app.is_application() or not self.checkbox_only_apps.isChecked()) app_model = PackageView(model=app, visible=app.is_application() or not self.checkbox_only_apps.isChecked())
available_types[app.get_type()] = app.get_type_icon_path() available_types[app.get_type()] = app.get_type_icon_path()
@@ -529,6 +535,17 @@ class ManageWindow(QWidget):
if as_installed: if as_installed:
self.pkgs_installed.append(app_model) self.pkgs_installed.append(app_model)
if old_installed and types:
for pkgv in old_installed:
if not pkgv.model.__class__ in types:
available_types[pkgv.model.get_type()] = pkgv.model.get_type_icon_path()
napps += 1 if pkgv.model.is_application() else 0
self.pkgs.append(pkgv)
if as_installed:
self.pkgs_installed.append(pkgv)
else: # use installed else: # use installed
self.pkgs = self.pkgs_installed self.pkgs = self.pkgs_installed
for app in self.pkgs: for app in self.pkgs:
@@ -607,11 +624,10 @@ class ManageWindow(QWidget):
if self.manager.requires_root('update', app_v.model): if self.manager.requires_root('update', app_v.model):
requires_root = True requires_root = True
bt_ex = UpdateToggleButton(None, self, self.locale_keys, clickable=False)
if to_update and dialog.ask_confirmation(title=self.locale_keys['manage_window.upgrade_all.popup.title'], if to_update and dialog.ask_confirmation(title=self.locale_keys['manage_window.upgrade_all.popup.title'],
body=self.locale_keys['manage_window.upgrade_all.popup.body'], body=self.locale_keys['manage_window.upgrade_all.popup.body'],
locale_keys=self.locale_keys, locale_keys=self.locale_keys,
widgets=[bt_ex]): widgets=[UpdateToggleButton(None, self, self.locale_keys, clickable=False)]):
pwd = None pwd = None
if not is_root() and requires_root: if not is_root() and requires_root:
@@ -633,7 +649,7 @@ class ManageWindow(QWidget):
if self._can_notify_user(): if self._can_notify_user():
util.notify_user('{} {}'.format(res['updated'], self.locale_keys['notification.update_selected.success'])) util.notify_user('{} {}'.format(res['updated'], self.locale_keys['notification.update_selected.success']))
self.refresh_apps() self.refresh_apps(pkg_types=res['types'])
if self.tray_icon: if self.tray_icon:
self.tray_icon.verify_updates() self.tray_icon.verify_updates()
@@ -691,9 +707,9 @@ class ManageWindow(QWidget):
self.combo_filter_type.setEnabled(True) self.combo_filter_type.setEnabled(True)
self.checkbox_updates.setEnabled(True) self.checkbox_updates.setEnabled(True)
def downgrade_app(self, app: PackageView): def downgrade_app(self, pkgv: PackageView):
pwd = None pwd = None
requires_root = self.manager.requires_root('downgrade', app.model) requires_root = self.manager.requires_root('downgrade', pkgv.model)
if not is_root() and requires_root: if not is_root() and requires_root:
pwd, ok = ask_root_password(self.locale_keys) pwd, ok = ask_root_password(self.locale_keys)
@@ -702,17 +718,17 @@ class ManageWindow(QWidget):
return return
self._handle_console_option(True) self._handle_console_option(True)
self._begin_action('{} {}'.format(self.locale_keys['manage_window.status.downgrading'], app.model.base_data.name)) self._begin_action('{} {}'.format(self.locale_keys['manage_window.status.downgrading'], pkgv.model.base_data.name))
self.thread_downgrade.app = app self.thread_downgrade.app = pkgv
self.thread_downgrade.root_password = pwd self.thread_downgrade.root_password = pwd
self.thread_downgrade.start() self.thread_downgrade.start()
def get_app_info(self, app: dict): def get_app_info(self, pkg: dict):
self._handle_console_option(False) self._handle_console_option(False)
self._begin_action(self.locale_keys['manage_window.status.info']) self._begin_action(self.locale_keys['manage_window.status.info'])
self.thread_get_info.app = app self.thread_get_info.app = pkg
self.thread_get_info.start() self.thread_get_info.start()
def get_app_history(self, app: dict): def get_app_history(self, app: dict):
@@ -786,7 +802,7 @@ class ManageWindow(QWidget):
if self._can_notify_user(): if self._can_notify_user():
util.notify_user(msg='{} ({}) {}'.format(app.model.base_data.name, app.model.get_type(), self.locale_keys['installed'])) util.notify_user(msg='{} ({}) {}'.format(app.model.base_data.name, app.model.get_type(), self.locale_keys['installed']))
self.refresh_apps(top_app=app) self.refresh_apps(top_app=app, pkg_types={app.model.__class__})
else: else:
if self._can_notify_user(): if self._can_notify_user():
util.notify_user('{}: {}'.format(app.model.base_data.name, self.locale_keys['notification.install.failed'])) util.notify_user('{}: {}'.format(app.model.base_data.name, self.locale_keys['notification.install.failed']))