[magneto] migrate to RigoDaemon, kill entropy-updates-service (RIP!)
This commit is contained in:
@@ -27,7 +27,7 @@ magneto-loader-install:
|
||||
mkdir -p $(DESTDIR)/$(LIBDIR)/entropy/magneto
|
||||
install -m644 $(MISCDIR)/*.desktop $(DESTDIR)/etc/xdg/autostart/.
|
||||
install -m644 $(MISCDIR)/*.desktop $(DESTDIR)$(PREFIX)/share/applications/.
|
||||
install -m755 src/magneto.py $(DESTDIR)/$(LIBDIR)/entropy/magneto/.
|
||||
install -m755 src/magneto_app.py $(DESTDIR)/$(LIBDIR)/entropy/magneto/magneto.py
|
||||
install -m755 $(MISCDIR)/magneto $(DESTDIR)$(BINDIR)/.
|
||||
|
||||
magneto-gtk-install:
|
||||
|
||||
@@ -17,6 +17,7 @@ import time
|
||||
import subprocess
|
||||
import dbus
|
||||
import dbus.exceptions
|
||||
from threading import Lock
|
||||
|
||||
# Entropy imports
|
||||
from entropy.output import nocolor
|
||||
@@ -29,6 +30,10 @@ from entropy.misc import ParallelTask
|
||||
# Magneto imports
|
||||
from magneto.core import config
|
||||
|
||||
# RigoDaemon imports
|
||||
from RigoDaemon.config import DbusConfig
|
||||
from RigoDaemon.enums import ActivityStates
|
||||
|
||||
class MagnetoCoreUI:
|
||||
|
||||
"""
|
||||
@@ -97,12 +102,26 @@ class MagnetoCore(MagnetoCoreUI):
|
||||
Magneto base UI interface, must be subclassed to make it support Qt/GTK
|
||||
interfaces.
|
||||
"""
|
||||
|
||||
_PING_SIGNAL = "ping"
|
||||
_UPDATES_AVAILABLE_SIGNAL = "updates_available"
|
||||
_ACTIVITY_STARTED_SIGNAL = "activity_started"
|
||||
_REPOSITORIES_UPDATED_SIGNAL = "repositories_updated"
|
||||
|
||||
DBUS_INTERFACE = DbusConfig.BUS_NAME
|
||||
DBUS_PATH = DbusConfig.OBJECT_PATH
|
||||
|
||||
def __init__(self, icon_loader_class, main_loop_class):
|
||||
|
||||
if "--debug" not in sys.argv:
|
||||
import signal
|
||||
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||
|
||||
self.__dbus_main_loop = None
|
||||
self.__system_bus = None
|
||||
self.__entropy_bus = None
|
||||
self.__entropy_bus_mutex = Lock()
|
||||
|
||||
# Set this to True when DBus service is up
|
||||
self._dbus_service_available = False
|
||||
# Notice Window Widget status
|
||||
@@ -131,11 +150,6 @@ class MagnetoCore(MagnetoCoreUI):
|
||||
|
||||
# Dbus variables
|
||||
self._dbus_init_error_msg = 'Unknown error'
|
||||
self._dbus_interface = "org.entropy.Client"
|
||||
self._dbus_path = "/notifier"
|
||||
self._signal_name = "signal_updates"
|
||||
self._updating_signal_name = "signal_updating"
|
||||
self._integrity_signal_name = "signal_integrity_problem"
|
||||
|
||||
self._menu_item_list = (
|
||||
("disable_applet", _("_Disable Notification Applet"),
|
||||
@@ -156,38 +170,118 @@ class MagnetoCore(MagnetoCoreUI):
|
||||
|
||||
self._main_loop_class = main_loop_class
|
||||
|
||||
@property
|
||||
def _dbus_main_loop(self):
|
||||
if self.__dbus_main_loop is None:
|
||||
self.__dbus_main_loop = self._main_loop_class(
|
||||
set_as_default=True)
|
||||
return self.__dbus_main_loop
|
||||
|
||||
@property
|
||||
def _system_bus(self):
|
||||
if self.__system_bus is None:
|
||||
self.__system_bus = dbus.SystemBus(
|
||||
mainloop=self._dbus_main_loop)
|
||||
return self.__system_bus
|
||||
|
||||
@property
|
||||
def _entropy_bus(self):
|
||||
with self.__entropy_bus_mutex:
|
||||
if self.__entropy_bus is None:
|
||||
self.__entropy_bus = self._system_bus.get_object(
|
||||
self.DBUS_INTERFACE, self.DBUS_PATH
|
||||
)
|
||||
|
||||
# ping/pong signaling, used to let
|
||||
# RigoDaemon release exclusive locks
|
||||
# when no client is connected
|
||||
self.__entropy_bus.connect_to_signal(
|
||||
self._PING_SIGNAL, self._ping_signal,
|
||||
dbus_interface=self.DBUS_INTERFACE)
|
||||
|
||||
# RigoDaemon is telling us that a new activity
|
||||
# has just begun
|
||||
self.__entropy_bus.connect_to_signal(
|
||||
self._ACTIVITY_STARTED_SIGNAL,
|
||||
self._activity_started_signal,
|
||||
dbus_interface=self.DBUS_INTERFACE)
|
||||
|
||||
# RigoDaemon tells us that there are app updates
|
||||
# available
|
||||
self.__entropy_bus.connect_to_signal(
|
||||
self._UPDATES_AVAILABLE_SIGNAL,
|
||||
self._updates_available_signal,
|
||||
dbus_interface=self.DBUS_INTERFACE)
|
||||
|
||||
self.__entropy_bus.connect_to_signal(
|
||||
self._REPOSITORIES_UPDATED_SIGNAL,
|
||||
self._repositories_updated_signal,
|
||||
dbus_interface=self.DBUS_INTERFACE)
|
||||
|
||||
return self.__entropy_bus
|
||||
|
||||
def setup_dbus(self):
|
||||
"""
|
||||
Dbus Setup method.
|
||||
"""
|
||||
tries = 5
|
||||
while tries:
|
||||
dbus_loop = self._main_loop_class(set_as_default = True)
|
||||
self._system_bus = dbus.SystemBus(mainloop = dbus_loop)
|
||||
try:
|
||||
self._entropy_dbus_object = self._system_bus.get_object(
|
||||
self._dbus_interface, self._dbus_path
|
||||
)
|
||||
self._entropy_dbus_object.connect_to_signal(
|
||||
self._signal_name, self.new_updates_signal,
|
||||
dbus_interface = self._dbus_interface
|
||||
)
|
||||
self._entropy_dbus_object.connect_to_signal(
|
||||
self._updating_signal_name, self.updating_signal,
|
||||
dbus_interface = self._dbus_interface
|
||||
)
|
||||
self._entropy_dbus_object.connect_to_signal(
|
||||
self._integrity_signal_name, self.integrity_signal,
|
||||
dbus_interface = self._dbus_interface)
|
||||
except dbus.exceptions.DBusException as e:
|
||||
self._dbus_init_error_msg = repr(e)
|
||||
# service not avail
|
||||
tries -= 1
|
||||
time.sleep(2)
|
||||
continue
|
||||
try:
|
||||
self._entropy_bus
|
||||
self._dbus_service_available = True
|
||||
return True
|
||||
entropy.tools.print_traceback()
|
||||
return False
|
||||
except dbus.exceptions.DBusException as err:
|
||||
self._dbus_service_available = False
|
||||
self._dbus_init_error_msg = "%s" % (err,)
|
||||
return False
|
||||
|
||||
def _ping_signal(self):
|
||||
"""
|
||||
Need to call pong() as soon as possible to hold all Entropy
|
||||
Resources allocated by RigoDaemon.
|
||||
"""
|
||||
dbus.Interface(
|
||||
self._entropy_bus,
|
||||
dbus_interface=self.DBUS_INTERFACE).pong()
|
||||
|
||||
def _activity_started_signal(self, activity):
|
||||
"""
|
||||
RigoDaemon is telling us that the scheduled activity,
|
||||
either by us or by another Rigo, has just begun and
|
||||
that it, RigoDaemon, has now exclusive access to
|
||||
Entropy Resources.
|
||||
"""
|
||||
if activity == ActivityStates.UPDATING_REPOSITORIES:
|
||||
self.updating_signal()
|
||||
|
||||
def _repositories_updated_signal(self, result, message):
|
||||
"""
|
||||
Repositories have been updated, ask for info
|
||||
"""
|
||||
self._hello()
|
||||
|
||||
def _hello(self):
|
||||
"""
|
||||
Say hello to RigoDaemon. This causes the sending of
|
||||
several welcome signals, such as updates notification.
|
||||
"""
|
||||
return dbus.Interface(
|
||||
self._entropy_bus,
|
||||
dbus_interface=self.DBUS_INTERFACE).hello()
|
||||
|
||||
def _update_repositories(self):
|
||||
"""
|
||||
Spawn Repositories Update on RigoDaemon.
|
||||
"""
|
||||
accepted = dbus.Interface(
|
||||
self._entropy_bus,
|
||||
dbus_interface=self.DBUS_INTERFACE).update_repositories(
|
||||
[], False)
|
||||
return accepted
|
||||
|
||||
def _updates_available_signal(self, update, update_atoms,
|
||||
remove, remove_atoms):
|
||||
if not update_atoms:
|
||||
return
|
||||
self.new_updates_signal(update_atoms)
|
||||
|
||||
def show_service_not_available(self):
|
||||
# inform user about missing Entropy service
|
||||
@@ -210,16 +304,14 @@ class MagnetoCore(MagnetoCoreUI):
|
||||
)
|
||||
)
|
||||
|
||||
def new_updates_signal(self):
|
||||
def new_updates_signal(self, update_atoms):
|
||||
if not config.settings['APPLET_ENABLED']:
|
||||
return
|
||||
iface = dbus.Interface(
|
||||
self._entropy_dbus_object, dbus_interface="org.entropy.Client")
|
||||
updates = iface.get_updates_atoms()
|
||||
avail = [str(x) for x in updates]
|
||||
|
||||
avail = [str(x) for x in update_atoms]
|
||||
del self.package_updates[:]
|
||||
self.package_updates.extend(avail)
|
||||
upd_len = len(updates)
|
||||
upd_len = len(update_atoms)
|
||||
|
||||
if upd_len:
|
||||
self.update_tooltip(ngettext("There is %s update available",
|
||||
@@ -256,15 +348,6 @@ class MagnetoCore(MagnetoCoreUI):
|
||||
_("Repositories are being updated automatically")
|
||||
)
|
||||
|
||||
def integrity_signal(self):
|
||||
# all fine, no updates
|
||||
self.update_tooltip(
|
||||
_("Installed Packages Repository Integrity Problem"))
|
||||
self.show_alert(
|
||||
_("Installed Packages Repository Integrity"),
|
||||
_("Integrity corruption detected, this might indicate a filesystem or system issue")
|
||||
)
|
||||
|
||||
def is_system_on_batteries(self):
|
||||
"""
|
||||
Return whether System is running on batteries.
|
||||
@@ -280,30 +363,6 @@ class MagnetoCore(MagnetoCoreUI):
|
||||
return True
|
||||
return False
|
||||
|
||||
def is_system_changed(self):
|
||||
|
||||
# enable applet if disabled
|
||||
if not config.settings['APPLET_ENABLED']:
|
||||
return False
|
||||
|
||||
# dbus daemon not available
|
||||
if not self._dbus_service_available:
|
||||
return False
|
||||
|
||||
iface = dbus.Interface(
|
||||
self._entropy_dbus_object, dbus_interface="org.entropy.Client")
|
||||
return iface.is_system_changed()
|
||||
|
||||
def send_keepalive(self):
|
||||
"""
|
||||
MagnetoCore users must spawn this function every 60 seconds (with a
|
||||
timer).
|
||||
"""
|
||||
if self._dbus_service_available:
|
||||
iface = dbus.Interface(
|
||||
self._entropy_dbus_object, dbus_interface="org.entropy.Client")
|
||||
iface.client_ping()
|
||||
|
||||
def send_check_updates_signal(self, widget=None, startup_check=False):
|
||||
|
||||
# enable applet if disabled
|
||||
@@ -320,12 +379,10 @@ class MagnetoCore(MagnetoCoreUI):
|
||||
self.last_trigger_check_t = cur_t
|
||||
|
||||
if self._dbus_service_available:
|
||||
iface = dbus.Interface(
|
||||
self._entropy_dbus_object, dbus_interface="org.entropy.Client")
|
||||
if startup_check:
|
||||
iface.trigger_check()
|
||||
self._hello()
|
||||
else:
|
||||
iface.trigger_startup_check()
|
||||
self._update_repositories()
|
||||
self.manual_check_triggered = True
|
||||
|
||||
def set_state(self, new_state, use_busy_icon = 0):
|
||||
@@ -371,17 +428,15 @@ class MagnetoCore(MagnetoCoreUI):
|
||||
self.load_url(etpConst['distro_website_url'])
|
||||
|
||||
def load_url(self, url):
|
||||
subprocess.call(['xdg-open', url])
|
||||
task = ParallelTask(
|
||||
subprocess.call, ['xdg-open', url])
|
||||
task.daemon = True
|
||||
task.start()
|
||||
|
||||
def launch_package_manager(self, *data):
|
||||
if os.access("/usr/bin/rigo", os.X_OK | os.R_OK):
|
||||
task = ParallelTask(subprocess.call, ["/usr/bin/rigo"])
|
||||
task.daemon = True
|
||||
task.start()
|
||||
elif os.access("/usr/bin/sulfur", os.X_OK | os.R_OK):
|
||||
task = ParallelTask(subprocess.call, ["/usr/bin/sulfur"])
|
||||
task.daemon = True
|
||||
task.start()
|
||||
task = ParallelTask(subprocess.call, ["/usr/bin/rigo"])
|
||||
task.daemon = True
|
||||
task.start()
|
||||
|
||||
def disable_applet(self):
|
||||
self.update_tooltip(_("Updates Notification Applet Disabled"))
|
||||
@@ -418,49 +473,4 @@ class MagnetoCore(MagnetoCoreUI):
|
||||
raise SystemExit(0)
|
||||
|
||||
def close_service(self):
|
||||
if self._dbus_service_available:
|
||||
iface = dbus.Interface(
|
||||
self._entropy_dbus_object, dbus_interface="org.entropy.Client")
|
||||
try:
|
||||
iface.close_connection()
|
||||
except dbus.exceptions.DBusException:
|
||||
pass
|
||||
entropy.tools.kill_threads()
|
||||
|
||||
class Entropy(Client):
|
||||
|
||||
"""
|
||||
@deprecated
|
||||
"""
|
||||
|
||||
def init_singleton(self, magneto):
|
||||
Client.init_singleton(self, installed_repo = False)
|
||||
self.__magneto = magneto
|
||||
self.progress_tooltip = self.__magneto.update_tooltip
|
||||
self.progress_tooltip_message_title = _("Updates Notification")
|
||||
self.applet_last_message = ''
|
||||
nocolor()
|
||||
|
||||
def output(self, text, header = "", footer = "", back = False,
|
||||
importance = 0, level = "info", count = [], percent = False):
|
||||
|
||||
count_str = ""
|
||||
if count:
|
||||
if percent:
|
||||
count_str = str(int(round((float(count[0])/count[1])*100, 1)))+"% "
|
||||
else:
|
||||
count_str = "(%s/%s) " % (str(count[0]), str(count[1]),)
|
||||
|
||||
message = count_str+_(text)
|
||||
#if importance in (1,2):
|
||||
if importance == 2:
|
||||
self.progress_tooltip_message_title = message
|
||||
self.__do_applet_print(self.applet_last_message)
|
||||
else:
|
||||
self.__do_applet_print(message)
|
||||
|
||||
def __do_applet_print(self, message):
|
||||
self.applet_last_message = message
|
||||
self.__magneto.show_alert(self.progress_tooltip_message_title,
|
||||
message)
|
||||
Client.__singleton_class__ = Entropy
|
||||
|
||||
@@ -72,17 +72,12 @@ class Magneto(MagnetoCore):
|
||||
|
||||
def __do_first_check(self):
|
||||
|
||||
# if system is running on batteries,
|
||||
# first check is skipped
|
||||
if self.is_system_on_batteries():
|
||||
return
|
||||
|
||||
def _do_check():
|
||||
self.send_check_updates_signal(startup_check=True)
|
||||
self.send_check_updates_signal(startup_check = True)
|
||||
return False
|
||||
|
||||
if self._dbus_service_available:
|
||||
# after 20 seconds
|
||||
# after 10 seconds
|
||||
gobject.timeout_add(10000, _do_check)
|
||||
|
||||
def startup(self):
|
||||
@@ -99,9 +94,6 @@ class Magneto(MagnetoCore):
|
||||
gobject.timeout_add(30000, self.show_service_available)
|
||||
self.__do_first_check()
|
||||
|
||||
# send Keep Alive signal
|
||||
self.__send_keepalive()
|
||||
|
||||
# Notice Window instance
|
||||
self._notice_window = AppletNoticeWindow(self)
|
||||
|
||||
@@ -111,14 +103,6 @@ class Magneto(MagnetoCore):
|
||||
gtk.main()
|
||||
gtk.gdk.threads_leave()
|
||||
|
||||
def __send_keepalive(self):
|
||||
"""
|
||||
As per MagnetoCore specs.
|
||||
"""
|
||||
gobject.timeout_add(60*1000, self.__send_keepalive)
|
||||
self.send_keepalive()
|
||||
return False
|
||||
|
||||
def close_service(self):
|
||||
MagnetoCore.close_service(self)
|
||||
gobject.timeout_add(0, gtk.main_quit)
|
||||
|
||||
@@ -94,25 +94,13 @@ class Magneto(MagnetoCore):
|
||||
|
||||
def __do_first_check(self):
|
||||
|
||||
# if system is running on batteries,
|
||||
# first check is skipped
|
||||
if self.is_system_on_batteries():
|
||||
return
|
||||
|
||||
def _do_check():
|
||||
self.send_check_updates_signal(startup_check=True)
|
||||
self.send_check_updates_signal(startup_check = True)
|
||||
return False
|
||||
|
||||
if self._dbus_service_available:
|
||||
QTimer.singleShot(10000, _do_check)
|
||||
|
||||
def __send_keepalive(self):
|
||||
"""
|
||||
As per MagnetoCore specs.
|
||||
"""
|
||||
QTimer.singleShot(60*1000, self.__send_keepalive)
|
||||
self.send_keepalive()
|
||||
|
||||
def startup(self):
|
||||
"""
|
||||
Start user interface.
|
||||
@@ -130,9 +118,6 @@ class Magneto(MagnetoCore):
|
||||
QTimer.singleShot(30000, self.show_service_available)
|
||||
self.__do_first_check()
|
||||
|
||||
# send Keep Alive signal
|
||||
self.__send_keepalive()
|
||||
|
||||
# Notice Window instance
|
||||
self._notice_window = AppletNoticeWindow(self)
|
||||
|
||||
|
||||
@@ -18,12 +18,14 @@ import time
|
||||
# point and will cause lock stealing.
|
||||
|
||||
def _startup():
|
||||
sys.path.insert(0, "/usr/lib/rigo")
|
||||
sys.path.insert(0, '/usr/lib/entropy/client')
|
||||
sys.path.insert(0, '/usr/lib/entropy/lib')
|
||||
sys.path.insert(0, '/usr/lib/entropy/magneto')
|
||||
sys.path.insert(0, '../rigo')
|
||||
sys.path.insert(0, '../../client')
|
||||
sys.path.insert(0, '../../lib')
|
||||
sys.path.insert(0, '../')
|
||||
sys.path.insert(0, './')
|
||||
|
||||
startup_delay = None
|
||||
for arg in sys.argv[1:]:
|
||||
@@ -57,6 +59,7 @@ def _startup():
|
||||
# load GTK
|
||||
from magneto.gtk.interfaces import Magneto
|
||||
|
||||
import entropy.tools
|
||||
magneto = Magneto()
|
||||
try:
|
||||
magneto.startup()
|
||||
@@ -1,14 +0,0 @@
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.entropy.Client">
|
||||
<method name="notifier"/>
|
||||
<method name="get_repo_status"/>
|
||||
<method name="trigger_check"/>
|
||||
<method name="trigger_startup_check"/>
|
||||
<method name="get_updates"/>
|
||||
<method name="get_updates_atoms"/>
|
||||
<method name="is_system_changed"/>
|
||||
<method name="close_connection"/>
|
||||
<method name="client_ping"/>
|
||||
</interface>
|
||||
</node>
|
||||
@@ -1,4 +0,0 @@
|
||||
[D-BUS Service]
|
||||
Name=org.entropy.Client
|
||||
Exec=/usr/sbin/client-updates-daemon
|
||||
User=root
|
||||
@@ -1,20 +0,0 @@
|
||||
<!DOCTYPE busconfig PUBLIC
|
||||
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
|
||||
<busconfig>
|
||||
<policy user="root">
|
||||
<allow own="org.entropy.Client"/>
|
||||
<allow send_destination="org.entropy.Client"/>
|
||||
<allow send_requested_reply="true"/>
|
||||
</policy>
|
||||
<policy group="entropy">
|
||||
<allow own="org.entropy.Client"/>
|
||||
<allow send_destination="org.entropy.Client"/>
|
||||
<allow send_requested_reply="true"/>
|
||||
</policy>
|
||||
<policy context="default">
|
||||
<allow send_requested_reply="true"/>
|
||||
<deny send_destination="org.entropy.Client"/>
|
||||
</policy>
|
||||
</busconfig>
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
lang_id="en_US.UTF-8"
|
||||
export LC_ALL="${lang_id}"
|
||||
export LANG="${lang_id}"
|
||||
export LANGUAGE="${lang_id}"
|
||||
|
||||
exec /usr/libexec/entropy-updates-service ${@}
|
||||
@@ -1,735 +0,0 @@
|
||||
#!/usr/bin/python2 -O
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
|
||||
@author: Fabio Erculiani <lxnay@sabayon.org>
|
||||
@contact: lxnay@sabayon.org
|
||||
@copyright: Fabio Erculiani
|
||||
@license: GPL-2
|
||||
|
||||
B{Entropy Package Manager Client service}.
|
||||
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
# this makes the daemon to not write the entropy pid file
|
||||
# avoiding to lock other instances
|
||||
sys.argv.append('--no-pid-handling')
|
||||
import time
|
||||
import gobject
|
||||
import dbus
|
||||
import dbus.service
|
||||
import dbus.mainloop.glib
|
||||
import signal
|
||||
import gc
|
||||
from threading import Lock, RLock
|
||||
|
||||
DAEMON_DEBUG = False
|
||||
if "--debug" in sys.argv:
|
||||
DAEMON_DEBUG = True
|
||||
|
||||
# Entropy imports
|
||||
sys.path.insert(0,'/usr/lib/entropy/lib')
|
||||
sys.path.insert(0,'/usr/lib/entropy/server')
|
||||
sys.path.insert(0,'/usr/lib/entropy/client')
|
||||
sys.path.insert(0,'../lib')
|
||||
sys.path.insert(0,'../server')
|
||||
sys.path.insert(0,'../client')
|
||||
|
||||
from entropy.cache import EntropyCacher
|
||||
# update default writeback timeout
|
||||
EntropyCacher.WRITEBACK_TIMEOUT = 120
|
||||
|
||||
from entropy.misc import LogFile
|
||||
from entropy.i18n import _
|
||||
from entropy.exceptions import PermissionDenied, RepositoryError, \
|
||||
SystemDatabaseError
|
||||
import entropy.tools as entropy_tools
|
||||
from entropy.client.interfaces import Client
|
||||
from entropy.fetchers import UrlFetcher
|
||||
from entropy.const import etpConst, const_setup_entropy_pid, \
|
||||
const_unsetup_entropy_pid, const_convert_to_rawstring, \
|
||||
const_drop_privileges, const_regain_privileges
|
||||
from entropy.core.settings.base import SystemSettings as SysSet
|
||||
from entropy.misc import ParallelTask
|
||||
from entropy.output import TextInterface, nocolor
|
||||
nocolor()
|
||||
|
||||
|
||||
SYS_SETTINGS = SysSet()
|
||||
TEXT = TextInterface()
|
||||
DAEMON_LOGFILE = os.path.join(etpConst['syslogdir'],"client-updater.log")
|
||||
DAEMON_LOG = LogFile(SYS_SETTINGS['system']['log_level']+1,
|
||||
DAEMON_LOGFILE, header = "[client-updater]")
|
||||
PREVIOUS_PROGRESS = ''
|
||||
CHECK_DELAY_SECS = 3600*4
|
||||
for xopt in sys.argv:
|
||||
if xopt.startswith("--secs=") and (len(xopt.split("=")) > 1):
|
||||
try:
|
||||
delay_secs = int(xopt.split("=")[1])
|
||||
CHECK_DELAY_SECS = delay_secs
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
if DAEMON_DEBUG:
|
||||
# redirect possible exception tracebacks to log file
|
||||
sys.stderr = DAEMON_LOG
|
||||
sys.stdout = DAEMON_LOG
|
||||
|
||||
def write_output(*args, **kwargs):
|
||||
message = time.strftime('[%H:%M:%S %d/%m/%Y %Z]') + " " + args[0]
|
||||
global PREVIOUS_PROGRESS
|
||||
if PREVIOUS_PROGRESS == message:
|
||||
return
|
||||
PREVIOUS_PROGRESS = message
|
||||
DAEMON_LOG.write(message)
|
||||
DAEMON_LOG.flush()
|
||||
if DAEMON_DEBUG:
|
||||
TEXT.output(*args, **kwargs)
|
||||
|
||||
def install_exception_handler():
|
||||
sys.excepthook = handle_exception
|
||||
|
||||
def uninstall_exception_handler():
|
||||
sys.excepthook = sys.__excepthook__
|
||||
|
||||
def handle_exception(exc_class, exc_instance, exc_tb):
|
||||
|
||||
t_back = entropy_tools.get_traceback(tb_obj = exc_tb)
|
||||
|
||||
# restore original exception handler, to avoid loops
|
||||
uninstall_exception_handler()
|
||||
# write exception to log file
|
||||
write_output(const_convert_to_rawstring(t_back))
|
||||
raise exc_instance
|
||||
|
||||
install_exception_handler()
|
||||
|
||||
class Privileges:
|
||||
|
||||
def __init__(self, drop_privs = True):
|
||||
self.__drop_privs = drop_privs
|
||||
self.__drop_privs_lock = RLock()
|
||||
self.__with_stmt = 0
|
||||
|
||||
def __enter__(self):
|
||||
"""
|
||||
Hold the lock.
|
||||
"""
|
||||
self.__drop_privs_lock.acquire()
|
||||
if self.__with_stmt < 1:
|
||||
self.regain()
|
||||
self.__with_stmt += 1
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
"""
|
||||
Drop the lock.
|
||||
"""
|
||||
if self.__with_stmt == 1:
|
||||
self.drop()
|
||||
self.__with_stmt -= 1
|
||||
self.__drop_privs_lock.release()
|
||||
|
||||
def drop(self):
|
||||
"""
|
||||
Drop process privileges. Setting unpriv_gid to etpConst['entropygid']
|
||||
makes Entropy UGC/Data cache handling working.
|
||||
"""
|
||||
if self.__drop_privs:
|
||||
with self.__drop_privs_lock:
|
||||
const_drop_privileges(unpriv_gid = etpConst['entropygid'])
|
||||
|
||||
def regain(self):
|
||||
"""
|
||||
Regain previously dropped process privileges.
|
||||
"""
|
||||
if self.__drop_privs:
|
||||
with self.__drop_privs_lock:
|
||||
const_regain_privileges()
|
||||
|
||||
class DaemonUrlFetcher(UrlFetcher):
|
||||
|
||||
daemon_last_avg = 100
|
||||
__average = 0
|
||||
__downloadedsize = 0
|
||||
__remotesize = 0
|
||||
__datatransfer = 0
|
||||
|
||||
def handle_statistics(self, th_id, downloaded_size, total_size,
|
||||
average, old_average, update_step, show_speed, data_transfer,
|
||||
time_remaining, time_remaining_secs):
|
||||
self.__average = average
|
||||
self.__downloadedsize = downloaded_size
|
||||
self.__remotesize = total_size
|
||||
self.__datatransfer = data_transfer
|
||||
|
||||
def update(self):
|
||||
myavg = abs(int(round(float(self.__average), 1)))
|
||||
if abs((myavg - self.daemon_last_avg)) < 1:
|
||||
return
|
||||
if int(myavg) % 10 == 0:
|
||||
DAEMON_LOG.write("fetch @ %s%s" % (myavg, "%",))
|
||||
self.daemon_last_avg = myavg
|
||||
|
||||
|
||||
class Entropy(Client):
|
||||
|
||||
def init_singleton(self):
|
||||
Client.init_singleton(self, load_ugc = False,
|
||||
url_fetcher = DaemonUrlFetcher, repo_validation = False)
|
||||
# validate currently available repos
|
||||
# manually, to not taint logs
|
||||
self._validate_repositories(quiet = True)
|
||||
self.output(
|
||||
"Loading Entropy Updates daemon: check every %ss, logfile: %s" % (
|
||||
CHECK_DELAY_SECS, DAEMON_LOGFILE,)
|
||||
)
|
||||
|
||||
def output(self, *args, **kwargs):
|
||||
return write_output(*args, **kwargs)
|
||||
Client.__singleton_class__ = Entropy
|
||||
|
||||
class UpdatesDaemon(dbus.service.Object):
|
||||
|
||||
def __init__(self):
|
||||
# start dbus service
|
||||
object_path = "/notifier"
|
||||
dbus_loop = dbus.mainloop.glib.DBusGMainLoop(set_as_default = True)
|
||||
system_bus = dbus.SystemBus(mainloop = dbus_loop)
|
||||
name = dbus.service.BusName("org.entropy.Client",
|
||||
bus = system_bus)
|
||||
dbus.service.Object.__init__(self, name, object_path)
|
||||
write_output("__init__: dbus service loaded")
|
||||
|
||||
# do not load/unload every time, this avoids
|
||||
# memleaks:
|
||||
# https://forum.sabayon.org/viewtopic.php?f=24&t=26171
|
||||
self._entropy = Entropy()
|
||||
self._privileges = Privileges()
|
||||
self._privileges.drop()
|
||||
self.__alive = False
|
||||
self.__is_working_mutex = Lock()
|
||||
self.__updater = None
|
||||
self.__entropy_cache_cleaner = None
|
||||
self.__entropy_integrity_checker = None
|
||||
self.__system_changes_checker = None
|
||||
self.__client_ping_checker = None
|
||||
self.__oncall_updater = None
|
||||
self.__quit_service_wd = None
|
||||
self.__quit_service_trigger = False
|
||||
self.__trigger_oncall_updater = False
|
||||
self.__trigger_disable_repos_update = False
|
||||
self.__trigger_startup_check = False
|
||||
self.__fetch_mutex = Lock()
|
||||
self.__updates = []
|
||||
self.__updates_atoms = None
|
||||
self.__system_db_hash = None
|
||||
self.__last_system_repo_checksum = None
|
||||
self.__got_client_ping = True
|
||||
|
||||
def start(self):
|
||||
self.stop()
|
||||
self.__alive = True
|
||||
self.__updater = gobject.timeout_add_seconds(
|
||||
CHECK_DELAY_SECS, self.run_fetcher)
|
||||
self.__oncall_updater = gobject.timeout_add_seconds(
|
||||
3, self.run_oncall_fetcher)
|
||||
self.__quit_service_wd = gobject.timeout_add_seconds(
|
||||
60, self.quit_service_watchdog)
|
||||
self.__system_changes_checker = gobject.timeout_add_seconds(
|
||||
120, self.check_system_changes)
|
||||
self.__entropy_cache_cleaner = gobject.timeout_add_seconds(
|
||||
3600, self.cleanup_entropy_cache)
|
||||
self.__entropy_integrity_checker = gobject.timeout_add_seconds(
|
||||
300, self.entropy_integrity_check)
|
||||
if "--disable-timer" not in sys.argv:
|
||||
self.__client_ping_checker = gobject.timeout_add_seconds(
|
||||
120, self.check_client_ping)
|
||||
|
||||
def stop(self):
|
||||
if self.__alive:
|
||||
self.__alive = False
|
||||
|
||||
if self.__updater is not None:
|
||||
gobject.source_remove(self.__updater)
|
||||
|
||||
if self.__system_changes_checker is not None:
|
||||
gobject.source_remove(self.__system_changes_checker)
|
||||
|
||||
if self.__oncall_updater is not None:
|
||||
gobject.source_remove(self.__oncall_updater)
|
||||
|
||||
if self.__quit_service_wd is not None:
|
||||
gobject.source_remove(self.__quit_service_wd)
|
||||
|
||||
if self.__client_ping_checker is not None:
|
||||
gobject.source_remove(self.__client_ping_checker)
|
||||
|
||||
if self.__entropy_cache_cleaner is not None:
|
||||
gobject.source_remove(self.__entropy_cache_cleaner)
|
||||
|
||||
if self.__entropy_integrity_checker is not None:
|
||||
gobject.source_remove(self.__entropy_integrity_checker)
|
||||
|
||||
def do_alert(self, string, msg, urgency = "critical"):
|
||||
write_output('alert: %s, %s, urgency: %s' % (string, msg, urgency,))
|
||||
|
||||
def is_system_on_batteries(self):
|
||||
"""
|
||||
Return whether System is running on batteries.
|
||||
|
||||
@return: True, if running on batteries
|
||||
@rtype: bool
|
||||
"""
|
||||
ac_powa_exec = "/usr/bin/on_ac_power"
|
||||
if not os.access(ac_powa_exec, os.X_OK):
|
||||
return False
|
||||
ex_rc = os.system(ac_powa_exec)
|
||||
if ex_rc:
|
||||
return True
|
||||
return False
|
||||
|
||||
def check_client_ping(self):
|
||||
if self.__got_client_ping:
|
||||
self.__got_client_ping = False
|
||||
else: # timeout!
|
||||
if DAEMON_DEBUG:
|
||||
write_output("check_client_ping: NO client ping, quitting")
|
||||
self.__quit_service_trigger = True
|
||||
return self.__alive
|
||||
|
||||
def cleanup_entropy_cache(self):
|
||||
|
||||
with self.__is_working_mutex:
|
||||
|
||||
with self._privileges:
|
||||
acquired = False
|
||||
try:
|
||||
acquired = self.__acquire_entropy_locks(self._entropy,
|
||||
pid_lock = False)
|
||||
if not acquired:
|
||||
return True # respawn later
|
||||
|
||||
if hasattr(self._entropy, 'clean_downloaded_packages'):
|
||||
self._entropy.clean_downloaded_packages()
|
||||
return False
|
||||
|
||||
finally:
|
||||
if acquired:
|
||||
self.__release_entropy_locks(self._entropy, pid_lock = False)
|
||||
|
||||
def entropy_integrity_check(self):
|
||||
|
||||
if self.is_system_on_batteries():
|
||||
# try again later
|
||||
return self.__alive
|
||||
|
||||
with self.__is_working_mutex:
|
||||
|
||||
with self._privileges:
|
||||
acquired = False
|
||||
try:
|
||||
acquired = self.__acquire_entropy_locks(self._entropy,
|
||||
pid_lock = False)
|
||||
if not acquired:
|
||||
return self.__alive # respawn later
|
||||
|
||||
inst_repo = self._entropy.installed_repository()
|
||||
if inst_repo is not None:
|
||||
try:
|
||||
inst_repo.integrity_check()
|
||||
except SystemDatabaseError:
|
||||
self.signal_integrity_problem()
|
||||
|
||||
# no need to run this further
|
||||
return False
|
||||
|
||||
finally:
|
||||
if acquired:
|
||||
self.__release_entropy_locks(self._entropy, pid_lock = False)
|
||||
|
||||
def check_system_changes(self):
|
||||
if self.__trigger_oncall_updater:
|
||||
return self.__alive
|
||||
|
||||
changed = self._is_system_changed()
|
||||
if changed:
|
||||
# this will disable repositories download, we don't really want
|
||||
# that in this case.
|
||||
self.__trigger_disable_repos_update = True
|
||||
# trigger check and push
|
||||
self.__trigger_oncall_updater = True
|
||||
# keep alive
|
||||
return self.__alive
|
||||
|
||||
def run_oncall_fetcher(self):
|
||||
|
||||
if not self.__trigger_oncall_updater:
|
||||
return self.__alive
|
||||
with self.__fetch_mutex:
|
||||
self.__trigger_oncall_updater = False
|
||||
update_repos = True
|
||||
if self.__trigger_disable_repos_update:
|
||||
update_repos = False
|
||||
self.__trigger_disable_repos_update = False
|
||||
task = ParallelTask(self.__run_fetcher, update_repos = update_repos)
|
||||
task.daemon = True
|
||||
task.start()
|
||||
#self.__run_fetcher()
|
||||
return self.__alive
|
||||
|
||||
def quit_service_watchdog(self):
|
||||
if self.__quit_service_trigger:
|
||||
self.stop()
|
||||
with self.__is_working_mutex:
|
||||
entropy_tools.kill_threads()
|
||||
raise SystemExit(0)
|
||||
return self.__alive
|
||||
|
||||
def run_fetcher(self):
|
||||
|
||||
if self.is_system_on_batteries():
|
||||
# running on batteries, then skip
|
||||
return self.__alive
|
||||
|
||||
with self.__fetch_mutex:
|
||||
task = ParallelTask(self.__run_fetcher)
|
||||
task.daemon = True
|
||||
task.start()
|
||||
#self.__run_fetcher()
|
||||
return self.__alive
|
||||
|
||||
def __run_sync(self, repos, entropy):
|
||||
|
||||
try:
|
||||
repo_conn = entropy.Repositories(
|
||||
repo_identifiers = repos, fetch_security = False,
|
||||
entropy_updates_alert = True)
|
||||
if DAEMON_DEBUG:
|
||||
write_output("__run_sync: repository interface loaded")
|
||||
except Exception, err:
|
||||
if DAEMON_DEBUG:
|
||||
write_output(
|
||||
"__run_sync: Unhandled exception, error: %s" % (err,))
|
||||
else:
|
||||
|
||||
# 128: sync error, something bad happened
|
||||
# 2: repositories not available (all)
|
||||
# 1: not able to update all the repositories
|
||||
if DAEMON_DEBUG:
|
||||
write_output("__run_sync: preparing to run sync")
|
||||
rc_res = repo_conn.sync()
|
||||
del repo_conn
|
||||
if DAEMON_DEBUG:
|
||||
write_output("__run_sync: sync done")
|
||||
|
||||
if rc_res == 1:
|
||||
err = _("Not all the repositories have been fetched")
|
||||
self.do_alert( _("Updates: repository issues"), err )
|
||||
return 0 # fine anyway
|
||||
elif rc_res == 2:
|
||||
err = _("No repositories found online")
|
||||
self.do_alert( _("Updates: repository issues"), err )
|
||||
return 0 # try to calculate updates anyway
|
||||
elif rc_res == 128:
|
||||
err = _("Synchronization errors. Cannot update repositories.")
|
||||
self.do_alert( _("Updates: sync issues"), err )
|
||||
return rc_res
|
||||
elif isinstance(rc_res, basestring):
|
||||
self.do_alert( _("Updates: unhandled error"), rc_res )
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
def __acquire_entropy_locks(self, entropy, pid_lock = True):
|
||||
|
||||
if pid_lock:
|
||||
acquired, locked = const_setup_entropy_pid(force_handling = True)
|
||||
if (not acquired) or locked:
|
||||
if DAEMON_DEBUG:
|
||||
if locked:
|
||||
write_output(
|
||||
"__acquire_entropy_locks: app. locked, skipping")
|
||||
else:
|
||||
write_output(
|
||||
"__acquire_entropy_locks: app. locked during acquire")
|
||||
return False
|
||||
|
||||
# entropy resources locked?
|
||||
acquired = entropy.lock_resources(blocking = False)
|
||||
if not acquired:
|
||||
if DAEMON_DEBUG:
|
||||
write_output(
|
||||
"__acquire_entropy_locks: resources locked, skipping")
|
||||
# reload installed packages repository
|
||||
entropy.close_repositories()
|
||||
entropy.reopen_installed_repository()
|
||||
# garbage collect
|
||||
count = gc.collect()
|
||||
if DAEMON_DEBUG:
|
||||
write_output("__acquire_entropy_locks: GC collected %s" % (count,))
|
||||
return acquired
|
||||
|
||||
def __release_entropy_locks(self, entropy, pid_lock = True):
|
||||
# unlock resources
|
||||
entropy.unlock_resources()
|
||||
if pid_lock:
|
||||
# remove application lock
|
||||
const_unsetup_entropy_pid()
|
||||
|
||||
def __run_fetcher(self, update_repos = True):
|
||||
|
||||
if self.__updater == None:
|
||||
return 0
|
||||
|
||||
with self.__is_working_mutex:
|
||||
|
||||
with self._privileges:
|
||||
|
||||
rc_fetch = 0
|
||||
acquired = False
|
||||
|
||||
try:
|
||||
|
||||
acquired = self.__acquire_entropy_locks(self._entropy,
|
||||
pid_lock = update_repos)
|
||||
if not acquired:
|
||||
return rc_fetch
|
||||
|
||||
if DAEMON_DEBUG:
|
||||
write_output("__run_fetcher: called %s" % (
|
||||
time.time(),))
|
||||
|
||||
if update_repos:
|
||||
repos_to_up = self.get_repo_status()
|
||||
if repos_to_up:
|
||||
|
||||
self.do_alert(
|
||||
_("Repositories to update"),
|
||||
unicode(repos_to_up),
|
||||
urgency = 'critical'
|
||||
)
|
||||
|
||||
if not self.__trigger_startup_check:
|
||||
gobject.timeout_add(0, self.signal_updating)
|
||||
repos = repos_to_up.keys()
|
||||
rc_fetch = self.__run_sync(repos, self._entropy)
|
||||
if rc_fetch != 0:
|
||||
return rc_fetch
|
||||
if DAEMON_DEBUG:
|
||||
write_output("__run_fetcher: sync closed, rc: %s" % (
|
||||
rc_fetch,))
|
||||
else:
|
||||
self.__trigger_startup_check = False
|
||||
if DAEMON_DEBUG:
|
||||
write_output("__run_fetcher: not syncing atm, "
|
||||
"trigger startup check is ON, waiting next "
|
||||
"round, repos: %s" % (repos_to_up,))
|
||||
|
||||
try:
|
||||
update, remove, fine, spm_fine = \
|
||||
self._entropy.calculate_updates(use_cache = False)
|
||||
del fine, remove
|
||||
except Exception, err:
|
||||
entropy_tools.print_traceback(f = DAEMON_LOG)
|
||||
msg = "%s: %s" % (_("Updates: error"), err,)
|
||||
self.do_alert(_("Updates: error"), msg)
|
||||
del self.__updates[:]
|
||||
self.__updates_atoms = None
|
||||
return 1
|
||||
|
||||
self.__system_db_hash = \
|
||||
self._entropy.installed_repository().checksum(
|
||||
do_order = True, strict = False)
|
||||
self.__updates = update[:]
|
||||
self.__updates_atoms = None
|
||||
|
||||
if update:
|
||||
self.do_alert(
|
||||
_("Updates available"),
|
||||
"%s %d %s" % (
|
||||
_("There are"), len(update),
|
||||
_("updates available."),),
|
||||
urgency = 'critical'
|
||||
)
|
||||
gobject.timeout_add(0, self.signal_updates)
|
||||
else:
|
||||
self.do_alert(
|
||||
_("No updates"),
|
||||
"%s" % (update,),
|
||||
urgency = 'critical'
|
||||
)
|
||||
gobject.timeout_add(0, self.signal_updates)
|
||||
|
||||
return 0
|
||||
|
||||
finally:
|
||||
if acquired:
|
||||
self.__release_entropy_locks(self._entropy,
|
||||
pid_lock = update_repos)
|
||||
|
||||
# compare repos status for updates
|
||||
@dbus.service.method ( "org.entropy.Client", in_signature = '',
|
||||
out_signature = 'a{si}')
|
||||
def get_repo_status(self):
|
||||
|
||||
repos = {}
|
||||
# now get remote
|
||||
sys_set = SysSet()
|
||||
for repoid in sys_set['repositories']['available']:
|
||||
|
||||
if DAEMON_DEBUG:
|
||||
write_output(
|
||||
"get_repo_status: scanning repository: %s" % (
|
||||
repoid,))
|
||||
|
||||
repo_rev = Entropy.get_repository(repoid).revision(repoid)
|
||||
online_rev = Entropy.get_repository(repoid).remote_revision(repoid)
|
||||
|
||||
if DAEMON_DEBUG:
|
||||
write_output(
|
||||
"get_repo_status: local rev: %s, remote rev: %s" % (
|
||||
repo_rev, online_rev,))
|
||||
|
||||
if (online_rev == -1) or (repo_rev != online_rev):
|
||||
|
||||
if DAEMON_DEBUG:
|
||||
write_output(
|
||||
"get_repo_status: repo needs to be updated: %s" % (
|
||||
repoid,))
|
||||
|
||||
sys_set._clear_repository_cache(repoid = repoid)
|
||||
repos[repoid] = {
|
||||
'local': repo_rev,
|
||||
'remote': online_rev,
|
||||
}
|
||||
|
||||
return repos
|
||||
|
||||
@dbus.service.method ( "org.entropy.Client", in_signature = '',
|
||||
out_signature = '')
|
||||
def trigger_check(self):
|
||||
self.__trigger_oncall_updater = True
|
||||
|
||||
@dbus.service.method ( "org.entropy.Client", in_signature = '',
|
||||
out_signature = '')
|
||||
def trigger_startup_check(self):
|
||||
self.__trigger_oncall_updater = True
|
||||
self.__trigger_startup_check = True
|
||||
|
||||
@dbus.service.method ( "org.entropy.Client", in_signature = '',
|
||||
out_signature = 'av')
|
||||
def get_updates(self):
|
||||
|
||||
curr_hash = self._entropy.installed_repository().checksum(
|
||||
do_order = True, strict = False)
|
||||
if curr_hash == self.__system_db_hash:
|
||||
return self.__updates
|
||||
|
||||
try:
|
||||
update, remove, fine, spm_fine = \
|
||||
self._entropy.calculate_updates(use_cache = False)
|
||||
except Exception, err:
|
||||
entropy_tools.print_traceback(f = DAEMON_LOG)
|
||||
msg = "get_updates: %s: %s" % (_("Updates: error"), err,)
|
||||
self.do_alert(_("Updates: error"), msg)
|
||||
return self.__updates
|
||||
|
||||
self.__updates = update[:]
|
||||
self.__system_db_hash = curr_hash
|
||||
return self.__updates
|
||||
|
||||
def _is_system_changed(self):
|
||||
with self.__is_working_mutex:
|
||||
|
||||
acquired = False
|
||||
try:
|
||||
acquired = self._entropy.lock_resources(blocking = False)
|
||||
if not acquired:
|
||||
if DAEMON_DEBUG:
|
||||
write_output(
|
||||
"_is_system_changed: resources locked!")
|
||||
# resources are locked, nothing changed yet :P
|
||||
return False
|
||||
|
||||
last_checksum = self.__last_system_repo_checksum
|
||||
cur_checksum = self._entropy.installed_repository().checksum(
|
||||
strict = False, strings = True)
|
||||
|
||||
changed = last_checksum != cur_checksum
|
||||
if DAEMON_DEBUG and changed:
|
||||
write_output(
|
||||
"_is_system_changed: system db checksum changed!")
|
||||
self.__last_system_repo_checksum = cur_checksum
|
||||
return changed
|
||||
finally:
|
||||
if acquired:
|
||||
self._entropy.unlock_resources()
|
||||
|
||||
@dbus.service.method("org.entropy.Client", in_signature = '',
|
||||
out_signature = 'b')
|
||||
def is_system_changed(self):
|
||||
return self._is_system_changed()
|
||||
|
||||
@dbus.service.method("org.entropy.Client", in_signature = '',
|
||||
out_signature = 'av')
|
||||
def get_updates_atoms(self):
|
||||
|
||||
if self.__updates_atoms is not None:
|
||||
return self.__updates_atoms
|
||||
|
||||
with self.__is_working_mutex:
|
||||
atoms = []
|
||||
self.__updates_atoms = []
|
||||
for idpackage, repoid in self.__updates:
|
||||
try:
|
||||
dbc = self._entropy.open_repository(repoid)
|
||||
atoms.append(dbc.retrieveAtom(idpackage))
|
||||
except RepositoryError:
|
||||
continue
|
||||
self.__updates_atoms.extend(atoms)
|
||||
return self.__updates_atoms
|
||||
|
||||
@dbus.service.method("org.entropy.Client", in_signature = '',
|
||||
out_signature = '')
|
||||
def client_ping(self):
|
||||
self.__got_client_ping = True
|
||||
if DAEMON_DEBUG:
|
||||
write_output("client_ping: got client ping")
|
||||
|
||||
# signal sent when updates are available for retrive
|
||||
@dbus.service.signal(dbus_interface = 'org.entropy.Client',
|
||||
signature = '')
|
||||
def signal_updates(self):
|
||||
if DAEMON_DEBUG:
|
||||
write_output("signal_updates: updates available!")
|
||||
return False
|
||||
|
||||
# signal sent when installed packages repository is corrupted
|
||||
@dbus.service.signal(dbus_interface = 'org.entropy.Client',
|
||||
signature = '')
|
||||
def signal_integrity_problem(self):
|
||||
if DAEMON_DEBUG:
|
||||
write_output("signal_integrity_problem: corrupted repository!")
|
||||
return False
|
||||
|
||||
# signal sent when daemon is updating the repositories
|
||||
@dbus.service.signal(dbus_interface = 'org.entropy.Client',
|
||||
signature = '')
|
||||
def signal_updating(self):
|
||||
if DAEMON_DEBUG:
|
||||
write_output("signal_updating: updating repos!")
|
||||
return False
|
||||
|
||||
if __name__ == "__main__":
|
||||
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||
try:
|
||||
ud_i = UpdatesDaemon()
|
||||
except dbus.exceptions.DBusException:
|
||||
raise SystemExit(1)
|
||||
gobject.threads_init()
|
||||
ud_i.start()
|
||||
main_loop = gobject.MainLoop()
|
||||
main_loop.run()
|
||||
ud_i.stop()
|
||||
raise SystemExit(0)
|
||||
Reference in New Issue
Block a user