diff --git a/rigo/RigoDaemon/app.py b/rigo/RigoDaemon/app.py
index 3479b69e0..26062a73c 100755
--- a/rigo/RigoDaemon/app.py
+++ b/rigo/RigoDaemon/app.py
@@ -436,7 +436,7 @@ class RigoDaemonService(dbus.service.Object):
BUS_NAME = DbusConfig.BUS_NAME
OBJECT_PATH = DbusConfig.OBJECT_PATH
- API_VERSION = 6
+ API_VERSION = 7
"""
RigoDaemon is the dbus service Object in charge of executing
@@ -2549,6 +2549,37 @@ class RigoDaemonService(dbus.service.Object):
outcome.append(obj)
return outcome
+ def _optimize_mirrors(self, repository_ids):
+ """
+ Execute a background Repository Mirrors optimization.
+ This low-priority method shall reorder Repository mirrors
+ basing on throughput performance.
+ It can be run in parallel with any other Entropy Client
+ activity since the operation is atomic.
+ """
+ optimized = False
+ for repository_id in repository_ids:
+
+ write_output("_optimize_mirrors: %s" % (
+ repository_id,), debug=True)
+
+ try:
+ repository_metadata = self._entropy.reorder_mirrors(
+ repository_id)
+ except KeyError as err:
+ write_output("_optimize_mirrors: "
+ "repository update error: %s" % (
+ repr(err),), debug=True)
+ continue
+
+ optimized = True
+ mirrors = repository_metadata.get('plain_packages')
+ write_output("_optimize_mirrors: repository "
+ "'%s' updated, mirrors: %s" % (
+ repository_id, mirrors), debug=True)
+
+ GLib.idle_add(self.mirrors_optimized, repository_ids, optimized)
+
### DBUS METHODS
@dbus.service.method(BUS_NAME, in_signature='asb',
@@ -3372,6 +3403,40 @@ class RigoDaemonService(dbus.service.Object):
task.start()
return True
+ @dbus.service.method(BUS_NAME, in_signature='as',
+ out_signature='b', sender_keyword='sender')
+ def optimize_mirrors(self, repository_ids, sender=None):
+ """
+ Request RigoDaeon to optimize Repository Mirrors
+ in background.
+ """
+ pid = self._get_caller_pid(sender)
+ write_output("optimize_mirrors called: "
+ "client pid: %s" % (
+ (pid,)), debug=True)
+
+ def _optimize(_repository_ids):
+ _repository_ids = [self._dbus_to_unicode(x) for \
+ x in _repository_ids]
+ authorized = self._authorize(
+ pid, PolicyActions.MANAGE_CONFIGURATION)
+ if authorized:
+ th = ParallelTask(
+ self._optimize_mirrors,
+ _repository_ids)
+ th.name = "OptimizeMirrorsThread"
+ th.daemon = True
+ th.start()
+ else:
+ GLib.idle_add(self.mirrors_optimized,
+ _repository_ids, False)
+
+ task = ParallelTask(_optimize, repository_ids)
+ task.name = "OptimizeMirrorsRequestThread"
+ task.daemon = True
+ task.start()
+ return True
+
### DBUS SIGNALS
@dbus.service.signal(dbus_interface=BUS_NAME,
@@ -3611,6 +3676,15 @@ class RigoDaemonService(dbus.service.Object):
write_output("old_repositories(): %s" % (locals(),),
debug=True)
+ @dbus.service.signal(dbus_interface=BUS_NAME,
+ signature='asb')
+ def mirrors_optimized(self, repository_ids, optimized):
+ """
+ Mirrors have been eventually optimized for given Repositories.
+ """
+ write_output("mirrors_optimized() issued, args:"
+ " %s" % (locals(),), debug=True)
+
@dbus.service.signal(dbus_interface=BUS_NAME,
signature='')
def ping(self):
diff --git a/rigo/RigoDaemon/dbus/org.sabayon.Rigo.xml b/rigo/RigoDaemon/dbus/org.sabayon.Rigo.xml
index effaaf7a2..4f1f11c93 100644
--- a/rigo/RigoDaemon/dbus/org.sabayon.Rigo.xml
+++ b/rigo/RigoDaemon/dbus/org.sabayon.Rigo.xml
@@ -112,5 +112,10 @@
+
+
+
+
+
diff --git a/rigo/data/icons/browser-download.svg b/rigo/data/icons/browser-download.svg
new file mode 100644
index 000000000..20485b467
--- /dev/null
+++ b/rigo/data/icons/browser-download.svg
@@ -0,0 +1,463 @@
+
+
+
+
diff --git a/rigo/rigo/controllers/daemon.py b/rigo/rigo/controllers/daemon.py
index c5f696991..92eeca81d 100644
--- a/rigo/rigo/controllers/daemon.py
+++ b/rigo/rigo/controllers/daemon.py
@@ -69,6 +69,7 @@ class RigoServiceController(GObject.Object):
SYSTEM_UPGRADE_CONTEXT_ID = "SystemUpgradeContextId"
PKG_INSTALL_CONTEXT_ID = "PackageInstallContextId"
REPOSITORY_SETTINGS_CONTEXT_ID = "RepositoriesSettingsContextId"
+ OPTIMIZE_MIRRORS_CONTEXT_ID = "MirrorsOptimizedContextId"
class ServiceNotificationBox(NotificationBox):
@@ -186,7 +187,8 @@ class RigoServiceController(GObject.Object):
_OLD_REPOSITORIES_SIGNAL = "old_repositories"
_NOTICEBOARDS_AVAILABLE_SIGNAL = "noticeboards_available"
_REPOS_SETTINGS_CHANGED_SIGNAL = "repositories_settings_changed"
- _SUPPORTED_APIS = [6]
+ _MIRRORS_OPTIMIZED_SIGNAL = "mirrors_optimized"
+ _SUPPORTED_APIS = [6, 7]
def __init__(self, rigo_app, activity_rwsem,
entropy_client, entropy_ws):
@@ -541,6 +543,13 @@ class RigoServiceController(GObject.Object):
self._repositories_settings_changed_signal,
dbus_interface=self.DBUS_INTERFACE)
+ # RigoDaemon tells us that mirros have been
+ # optimized
+ self.__entropy_bus.connect_to_signal(
+ self._MIRRORS_OPTIMIZED_SIGNAL,
+ self._mirrors_optimized_signal,
+ dbus_interface=self.DBUS_INTERFACE)
+
return self.__entropy_bus
### GOBJECT EVENTS
@@ -1085,6 +1094,30 @@ class RigoServiceController(GObject.Object):
__name__,
"_repositories_updated_signal: repositories-updated")
+ def _mirrors_optimized_signal(self, repository_ids, optimized):
+
+ repository_ids = [self._dbus_to_unicode(x) for x in \
+ repository_ids]
+
+ const_debug_write(
+ __name__,
+ "_mirrors_optimized_signal: received for "
+ "%s, optimized: %s" % (repository_ids, optimized,))
+
+ if optimized:
+ msg = prepare_markup(
+ _("Congratulations, mirrors have been optimized!"))
+ msg_type = Gtk.MessageType.INFO
+ else:
+ msg = prepare_markup(
+ _("Ouch, mirrors not optimized, sorry!"))
+ msg_type = Gtk.MessageType.WARNING
+
+ box = self.ServiceNotificationBox(
+ msg, msg_type,
+ context_id=self.OPTIMIZE_MIRRORS_CONTEXT_ID)
+ self._nc.append(box, timeout=30)
+
def _output_signal(self, text, header, footer, back, importance, level,
count_c, count_t, percent, raw):
"""
@@ -1466,6 +1499,37 @@ class RigoServiceController(GObject.Object):
task.daemon = True
task.start()
+ def optimize_mirrors(self, repository_ids):
+ """
+ Request mirror list optimization (basically
+ sorting per throughput) for the given
+ Repositories.
+ """
+ if self.api() < 7:
+ # ignore request, RigoDaemon is too old
+ return
+
+ def _optimize():
+ accepted = dbus.Interface(
+ self._entropy_bus,
+ dbus_interface=self.DBUS_INTERFACE
+ ).optimize_mirrors(repository_ids)
+ if accepted:
+ msg = prepare_markup(
+ _("Mirrors will be optimized in background..."))
+ msg_type = Gtk.MessageType.INFO
+ else:
+ msg = prepare_markup(
+ _("Mirrors optimization not available at this time"))
+ msg_type = Gtk.MessageType.WARNING
+ box = self.ServiceNotificationBox(
+ msg, msg_type,
+ context_id=self.OPTIMIZE_MIRRORS_CONTEXT_ID)
+ self._nc.append(box, timeout=30)
+ return accepted
+
+ return self._execute_mainloop(_optimize)
+
def configuration_updates(self):
"""
Request pending Configuration File Updates.
diff --git a/rigo/rigo/ui/gtk3/controllers/applications.py b/rigo/rigo/ui/gtk3/controllers/applications.py
index 6b83663bf..aa380a134 100644
--- a/rigo/rigo/ui/gtk3/controllers/applications.py
+++ b/rigo/rigo/ui/gtk3/controllers/applications.py
@@ -446,6 +446,14 @@ class ApplicationsViewController(GObject.Object):
if sim_str:
self.remove(sim_str)
+ def _do_optimize_mirrors():
+ self._entropy.rwsem().reader_acquire()
+ try:
+ repository_ids = self._entropy.repositories()
+ finally:
+ self._entropy.rwsem().reader_release()
+ self._service.optimize_mirrors(repository_ids)
+
special_keys_map = {
"in:confupdate": self._service.configuration_updates,
self.SHOW_QUEUE_KEY: self._show_action_queue_items,
@@ -463,6 +471,7 @@ class ApplicationsViewController(GObject.Object):
"do:remove": _do_remove,
"do:upgrade": self.upgrade,
"do:hello": self._service.hello,
+ "do:optimize": _do_optimize_mirrors,
}
special_f = special_keys_map.get(split_text[0])
@@ -717,11 +726,25 @@ class ApplicationsViewController(GObject.Object):
self._search(ApplicationsViewController.SHOW_INSTALLED_KEY,
_force=True)
pref = Preference(
- -1, _("Show Installed Applications"),
+ -2, _("Show Installed Applications"),
_("Browse through the currently Installed Applications."),
"drive-harddisk", _show_installed)
self._prefc.append(pref)
+ def _optimize_mirrors():
+ self._entropy.rwsem().reader_acquire()
+ try:
+ repository_ids = self._entropy.repositories()
+ finally:
+ self._entropy.rwsem().reader_release()
+ self._service.optimize_mirrors(repository_ids)
+ pref = Preference(
+ 50, _("Optimize Download Speed"),
+ _("Benchmark the download mirrors to speed up Application"
+ " installation."),
+ "browser-download", _optimize_mirrors)
+ self._prefc.append(pref)
+
def _show_queue_view(widget):
self._search(ApplicationsViewController.SHOW_QUEUE_KEY,
_force=True)