[RigoDaemon] feed App Management notes to clients, bump API

Update Rigo as well and let it push the notes to the Terminal Widget
(they come from stdout and stderr, sorry)
This commit is contained in:
Fabio Erculiani
2012-04-17 19:53:57 +02:00
parent 5968ee99c4
commit 5400519abc
2 changed files with 132 additions and 14 deletions

View File

@@ -11,6 +11,7 @@
"""
import os
import stat
# entropy.i18n will pick this up
os.environ['ETP_GETTEXT_DOMAIN'] = "rigo"
@@ -265,8 +266,10 @@ class FakeOutFile(object):
Fake Standard Output / Error file object
"""
def __init__(self, entropy_client):
def __init__(self, entropy_client, app_mgmt_mutex, app_mgmt_notes):
self._entropy = entropy_client
self._app_mgmt_mutex = app_mgmt_mutex
self._app_mgmt_notes = app_mgmt_notes
self._rfd, self._wfd = os.pipe()
task = ParallelTask(self._pusher)
task.name = "FakeOutFilePusher"
@@ -282,6 +285,16 @@ class FakeOutFile(object):
if err.errno == errno.EINTR:
continue
raise
# record to App Management Log, if enabled
with self._app_mgmt_mutex:
fobj = self._app_mgmt_notes['fobj']
if fobj is not None:
try:
fobj.write(chunk)
except (OSError, IOError) as err:
write_output("_pusher thread: "
"cannot write to app log: "
"%s" % (repr(err),))
self._entropy.output(chunk, _raw=True)
def close(self):
@@ -376,7 +389,7 @@ class RigoDaemonService(dbus.service.Object):
BUS_NAME = DbusConfig.BUS_NAME
OBJECT_PATH = DbusConfig.OBJECT_PATH
API_VERSION = 3
API_VERSION = 4
"""
RigoDaemon is the dbus service Object in charge of executing
@@ -548,9 +561,18 @@ class RigoDaemonService(dbus.service.Object):
self._deferred_shutdown = False
self._deferred_shutdown_mutex = Lock()
self._app_mgmt_mutex = Lock()
self._app_mgmt_notes = {
'fobj': None,
'path': None
}
Entropy.set_daemon(self)
self._entropy = Entropy()
self._fakeout = FakeOutFile(self._entropy)
self._fakeout = FakeOutFile(
self._entropy,
self._app_mgmt_mutex,
self._app_mgmt_notes)
executable_path = sys.argv[0]
write_output(
@@ -1177,6 +1199,41 @@ class RigoDaemonService(dbus.service.Object):
# put it back
self._action_queue_waiter.release()
else:
# before unbusy, read App Management Notes
with self._app_mgmt_mutex:
# 0o644
perms = stat.S_IREAD | stat.S_IWRITE \
| stat.S_IRGRP | stat.S_IROTH
fobj = self._app_mgmt_notes['fobj']
app_log_path = self._app_mgmt_notes['path']
if fobj is not None:
try:
fobj.close()
except OSError:
write_output(
"_action_queue_finally: "
"unexpected close() error %s" % (
repr(err),))
self._app_mgmt_notes['fobj'] = None
# root is already owning it
try:
os.chmod(app_log_path, perms)
except OSError as err:
if err.errno == errno.ENOENT:
# wtf, file vanished?
app_log_path = ""
elif err.errno == errno.EPERM:
# somebody changed the permissions
app_log_path = ""
else:
write_output(
"_action_queue_finally: "
"unexpected error %s" % (repr(err),))
app_log_path = ""
try:
self._unbusy(activity)
except ActivityStates.AlreadyAvailableError:
@@ -1193,7 +1250,7 @@ class RigoDaemonService(dbus.service.Object):
GLib.idle_add(
self.activity_completed, activity, success)
GLib.idle_add(
self.applications_managed, outcome)
self.applications_managed, outcome, app_log_path)
self._maybe_signal_configuration_updates()
is_app = True
@@ -2403,8 +2460,10 @@ class RigoDaemonService(dbus.service.Object):
self._enqueue_action_busy_hold_sem.acquire()
try:
activity = ActivityStates.MANAGING_APPLICATIONS
busied = False
try:
self._busy(activity)
busied = True
except ActivityStates.BusyError:
# I am already busy doing other stuff, cannot
# satisfy request
@@ -2416,6 +2475,39 @@ class RigoDaemonService(dbus.service.Object):
"already busy, just enqueue",
debug=True)
if busied:
# Setup Application Management
# Install/Remove notes
tmp_fd, tmp_path = tempfile.mkstemp(
prefix="RigoDaemonAppMgmt",
suffix=".notes")
with self._app_mgmt_mutex:
fobj = self._app_mgmt_notes['fobj']
path = self._app_mgmt_notes['path']
if fobj is not None:
try:
fobj.close()
except (OSError, IOError):
write_output(
"enqueue_application_action: "
"busied, but cannot close previous fd")
if path is not None:
try:
os.remove(path)
except (OSError, IOError):
write_output(
"enqueue_application_action: "
"busied, but cannot remove previous path")
try:
fobj = os.fdopen(tmp_fd, "w")
except OSError as err:
write_output(
"enqueue_application_action: "
"cannot open tmp_fd: %s" % (repr(err),))
fobj = None
self._app_mgmt_notes['fobj'] = fobj
self._app_mgmt_notes['path'] = tmp_path
task = ParallelTask(
self._enqueue_application_action_internal,
pid, package_id, repository_id, package_path,
@@ -2902,8 +2994,8 @@ class RigoDaemonService(dbus.service.Object):
" %s" % (locals(),), debug=True)
@dbus.service.signal(dbus_interface=BUS_NAME,
signature='s')
def applications_managed(self, outcome):
signature='ss')
def applications_managed(self, outcome, app_log_path):
"""
Enqueued Application actions have been completed.
"""

View File

@@ -18,8 +18,9 @@ You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
"""
import sys
import time
import codecs
from threading import Lock, Semaphore, current_thread
from collections import deque
@@ -178,7 +179,7 @@ class RigoServiceController(GObject.Object):
_UNAVAILABLE_REPOSITORIES_SIGNAL = "unavailable_repositories"
_OLD_REPOSITORIES_SIGNAL = "old_repositories"
_NOTICEBOARDS_AVAILABLE_SIGNAL = "noticeboards_available"
_SUPPORTED_APIS = [3]
_SUPPORTED_APIS = [4]
def __init__(self, rigo_app, activity_rwsem,
entropy_client, entropy_ws):
@@ -709,7 +710,8 @@ class RigoServiceController(GObject.Object):
box.add_button(_("Show me"), _show_me)
self._nc.append(box)
def _applications_managed_signal(self, outcome, local_activity):
def _applications_managed_signal(self, outcome, app_log_path,
local_activity):
"""
Signal coming from RigoDaemon notifying us that the
MANAGING_APPLICATIONS is over.
@@ -759,6 +761,28 @@ class RigoServiceController(GObject.Object):
if outcome != DaemonAppTransactionOutcome.SUCCESS:
self._notify_app_management_outcome(None, outcome)
# Send Application Management notes to Terminal.
if app_log_path:
enc = etpConst['conf_encoding']
app_notes = None
try:
with codecs.open(app_log_path, encoding=enc) as log_f:
app_notes = log_f.read()
except (IOError, OSError,) as err:
const_debug_write(
__name__,
"_applications_managed_signal: "
"cannot read app_log_path: %s" % (repr(err),))
if app_notes is not None:
if len(app_notes) > 3: # chars
if self._terminal is not None:
self._terminal.reset()
self._output_signal(
app_notes, None, None, False, 0, "info",
0, 0, False, True)
if self._wc is not None:
self._wc.expand_terminal()
# we don't expect to fail here, it would
# mean programming error.
self.unbusy(local_activity)
@@ -2154,14 +2178,15 @@ class RigoServiceController(GObject.Object):
signal_sem = Semaphore(1)
def _applications_managed_signal(outcome):
def _applications_managed_signal(outcome, app_log_path):
if not signal_sem.acquire(False):
# already called, no need to call again
return
# this is done in order to have it called
# only once by two different code paths
self._applications_managed_signal(
outcome, LocalActivityStates.MANAGING_APPLICATIONS)
outcome, app_log_path,
LocalActivityStates.MANAGING_APPLICATIONS)
with self._registered_signals_mutex:
# connect our signal
@@ -2252,7 +2277,7 @@ class RigoServiceController(GObject.Object):
# callback in random threads.
GLib.idle_add(self._applications_managed_signal,
DaemonAppTransactionOutcome.SUCCESS,
local_activity)
"", local_activity)
def _package_install_request(self, package_path, simulate=False):
"""
@@ -2492,14 +2517,15 @@ class RigoServiceController(GObject.Object):
signal_sem = Semaphore(1)
def _applications_managed_signal(outcome):
def _applications_managed_signal(outcome, app_log_path):
if not signal_sem.acquire(False):
# already called, no need to call again
return
# this is done in order to have it called
# only once by two different code paths
self._applications_managed_signal(
outcome, LocalActivityStates.UPGRADING_SYSTEM)
outcome, app_log_path,
LocalActivityStates.UPGRADING_SYSTEM)
with self._registered_signals_mutex:
# connect our signal