From ade10e0b8e5571e45cdd4800927c24597e2f7315 Mon Sep 17 00:00:00 2001
From: necoro <>
Date: Sun, 12 Aug 2007 04:21:38 +0000
Subject: added listener/notify
---
portato/__init__.py | 3 +
portato/constants.py | 7 +
portato/gui/gtk/__init__.py | 3 +
portato/gui/gtk/windows.py | 111 +++++-----
portato/gui/templates/portato.glade | 420 ++++++++++++++++++------------------
portato/helper.py | 17 +-
portato/plistener.py | 127 +++++++++++
portato/plugin.py | 3 +
portato/plugins/etc_proposals.py | 3 +-
portato/plugins/noroot.py | 15 --
portato/plugins/notify.py | 23 ++
11 files changed, 427 insertions(+), 305 deletions(-)
create mode 100644 portato/plistener.py
delete mode 100644 portato/plugins/noroot.py
create mode 100644 portato/plugins/notify.py
(limited to 'portato')
diff --git a/portato/__init__.py b/portato/__init__.py
index f10b9ef..57dd691 100644
--- a/portato/__init__.py
+++ b/portato/__init__.py
@@ -55,3 +55,6 @@ handler.setFormatter(formatter)
logging.getLogger("portatoLogger").addHandler(handler)
logging.getLogger("portatoLogger").setLevel(logging.DEBUG)
logging.getLogger("portatoLogger").propagate = False
+
+from plistener import PListener
+listener = PListener()
diff --git a/portato/constants.py b/portato/constants.py
index c21b0a5..309b774 100644
--- a/portato/constants.py
+++ b/portato/constants.py
@@ -38,6 +38,10 @@ These should be set during the installation.
@type FRONTENDS: string[]
@var STD_FRONTEND: the frontend uses as the default, i.e. if no other one is given on the cmdline
@type STD_FRONTEND: string
+@var SU_COMMAND: command to execute to "su"
+@type SU_COMMAND: string
+@var SOCKET: path to socket for communication between listener and GUI
+@type SOCKET: string
"""
from os.path import join as pjoin
@@ -60,3 +64,6 @@ LOCALE_DIR = "i18n/"
FRONTENDS = ["gtk" ,"qt"]
STD_FRONTEND = "gtk"
+
+SU_COMMAND = "gksu -D 'Portato'"
+SOCKET = "/tmp/portato.socket"
diff --git a/portato/gui/gtk/__init__.py b/portato/gui/gtk/__init__.py
index 0714f39..ba49652 100644
--- a/portato/gui/gtk/__init__.py
+++ b/portato/gui/gtk/__init__.py
@@ -12,6 +12,7 @@
from gettext import lgettext as _
+from portato import listener
from exception_handling import register_ex_handler
def run ():
@@ -27,6 +28,8 @@ def run ():
except KeyboardInterrupt:
pass
+ listener.close()
+
def show_ebuild (pkg):
import gtk
from portato import plugin
diff --git a/portato/gui/gtk/windows.py b/portato/gui/gtk/windows.py
index 74f7058..f0b7f1b 100644
--- a/portato/gui/gtk/windows.py
+++ b/portato/gui/gtk/windows.py
@@ -20,6 +20,7 @@ from subprocess import Popen
from gettext import lgettext as _
# our backend stuff
+from portato import listener
from portato.helper import *
from portato.constants import CONFIG_LOCATION, VERSION, APP_ICON
from portato.backend import flags, system
@@ -335,7 +336,7 @@ class PreferenceWindow (AbstractDialog):
self.cfg.set("consolefont", font, section = "GTK")
self.set_console_font(font)
- gtk.link_button_set_uri_hook(lambda btn, x: Popen([self.cfg.get("browserCmd", section = "GUI"), btn.get_uri()]))
+ gtk.link_button_set_uri_hook(lambda btn, x: listener.send_cmd([self.cfg.get("browserCmd", section = "GUI"), btn.get_uri()]))
def cb_ok_clicked(self, button):
"""Saves, writes to config-file and closes the window."""
@@ -717,20 +718,14 @@ class PackageTable:
def cb_package_emerge_clicked (self, button):
"""Callback for pressed emerge-button. Adds the package to the EmergeQueue."""
- if not am_i_root():
- not_root_dialog()
- else:
- self._update_keywords(True)
- self.main.notebook.set_current_page(self.main.QUEUE_PAGE)
+ self._update_keywords(True)
+ self.main.notebook.set_current_page(self.main.QUEUE_PAGE)
return True
def cb_package_unmerge_clicked (self, button):
"""Callback for pressed unmerge-button clicked. Adds the package to the UnmergeQueue."""
- if not am_i_root():
- not_root_dialog()
- else:
- self._update_keywords(False)
- self.main.notebook.set_current_page(self.main.QUEUE_PAGE)
+ self._update_keywords(False)
+ self.main.notebook.set_current_page(self.main.QUEUE_PAGE)
return True
def cb_package_ebuild_clicked(self, button):
@@ -900,7 +895,7 @@ class MainWindow (Window):
raise
self.cfg.modify_external_configs()
- gtk.link_button_set_uri_hook(lambda btn, x: Popen([self.cfg.get("browserCmd", section = "GUI"), btn.get_uri()]))
+ gtk.link_button_set_uri_hook(lambda btn, x: listener.send_cmd([self.cfg.get("browserCmd", section = "GUI"), btn.get_uri()]))
# set plugins and plugin-menu
splash(_("Loading Plugins"))
@@ -1177,47 +1172,43 @@ class MainWindow (Window):
return True
def cb_update_clicked (self, action):
- if not am_i_root():
- not_root_dialog()
- else:
+ def __update():
- def __update():
-
- def cb_idle_append (pkg, unmask):
- self.queue.append(pkg.get_cpv(), unmask = unmask)
- return False
+ def cb_idle_append (pkg, unmask):
+ self.queue.append(pkg.get_cpv(), unmask = unmask)
+ return False
- def cb_idle_unmask_dialog (e, updating):
- if unmask_dialog(e[0]) == gtk.RESPONSE_YES:
- for pkg, old_pkg in updating:
- self.queue.append(pkg.get_cpv(), unmask = True)
- return False
+ def cb_idle_unmask_dialog (e, updating):
+ if unmask_dialog(e[0]) == gtk.RESPONSE_YES:
+ for pkg, old_pkg in updating:
+ self.queue.append(pkg.get_cpv(), unmask = True)
+ return False
- def cb_idle_blocked(e):
- blocked_dialog(e[0], e[1])
- self.queue.remove_children(self.queue.emergeIt)
- return False
+ def cb_idle_blocked(e):
+ blocked_dialog(e[0], e[1])
+ self.queue.remove_children(self.queue.emergeIt)
+ return False
- watch = gtk.gdk.Cursor(gtk.gdk.WATCH)
- self.window.window.set_cursor(watch)
+ watch = gtk.gdk.Cursor(gtk.gdk.WATCH)
+ self.window.window.set_cursor(watch)
+ try:
+ updating = system.update_world(newuse = self.cfg.get_boolean("newuse"), deep = self.cfg.get_boolean("deep"))
+ debug("updating list: %s --> length: %s", [(x.get_cpv(), y.get_cpv()) for x,y in updating], len(updating))
try:
- updating = system.update_world(newuse = self.cfg.get_boolean("newuse"), deep = self.cfg.get_boolean("deep"))
- debug("updating list: %s --> length: %s", [(x.get_cpv(), y.get_cpv()) for x,y in updating], len(updating))
try:
- try:
- for pkg, old_pkg in updating:
- gobject.idle_add(cb_idle_append, pkg, False)
- except PackageNotFoundException, e:
- gobject.idle_add(cb_idle_unmask_dialog, e, updating)
-
- except BlockedException, e:
- gobject.idle_add(cb_idle_blocked(e))
-
- if len(updating): self.doUpdate = True
- finally:
- self.window.window.set_cursor(None)
+ for pkg, old_pkg in updating:
+ gobject.idle_add(cb_idle_append, pkg, False)
+ except PackageNotFoundException, e:
+ gobject.idle_add(cb_idle_unmask_dialog, e, updating)
- GtkThread(name="Update-Thread", target=__update).start()
+ except BlockedException, e:
+ gobject.idle_add(cb_idle_blocked(e))
+
+ if len(updating): self.doUpdate = True
+ finally:
+ self.window.window.set_cursor(None)
+
+ GtkThread(name="Update-Thread", target=__update).start()
return True
@@ -1245,26 +1236,20 @@ class MainWindow (Window):
return True
def cb_sync_clicked (self, action):
- if not am_i_root():
- not_root_dialog()
- else:
- self.notebook.set_current_page(self.CONSOLE_PAGE)
- cmd = self.cfg.get("syncCmd")
+ self.notebook.set_current_page(self.CONSOLE_PAGE)
+ cmd = self.cfg.get("syncCmd")
- if cmd != "emerge --sync":
- cmd = cmd.split()
- self.queue.sync(cmd)
- else:
- self.queue.sync()
+ if cmd != "emerge --sync":
+ cmd = cmd.split()
+ self.queue.sync(cmd)
+ else:
+ self.queue.sync()
def cb_save_flags_clicked (self, action):
- if not am_i_root():
- not_root_dialog()
- else:
- flags.write_use_flags()
- flags.write_testing()
- flags.write_masked()
-
+ flags.write_use_flags()
+ flags.write_testing()
+ flags.write_masked()
+
@Window.watch_cursor
def cb_reload_clicked (self, action):
"""Reloads the portage settings and the database."""
diff --git a/portato/gui/templates/portato.glade b/portato/gui/templates/portato.glade
index fe57c9a..77f8a8f 100644
--- a/portato/gui/templates/portato.glade
+++ b/portato/gui/templates/portato.glade
@@ -450,107 +450,52 @@
5
3
-
+
True
- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ 1
+ True
-
+
+ True
+ True
+ Installed
+ 0
+ True
+
+
+
+ False
+
-
-
- 3
- 1
- 2
- GTK_EXPAND
-
-
-
-
-
- True
- True
- <b>Installed, but not in portage anymore</b>
- True
-
-
- 3
- 2
- 3
- GTK_FILL
-
-
-
-
- True
- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
- 5
-
+
True
- True
- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
- GTK_POLICY_NEVER
- GTK_POLICY_AUTOMATIC
-
-
- True
- True
- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
- True
- False
-
-
-
+ True
+ Masked
+ 0
+ True
+
- False
+ False
+ 1
-
+
True
- False
- GTK_POLICY_AUTOMATIC
- GTK_POLICY_AUTOMATIC
-
-
- True
-
-
+ True
+ Testing
+ 0
+ True
+
- 1
+ False
+ 2
-
- 3
- 3
- 4
- 5
- 5
-
-
-
-
- True
- GTK_JUSTIFY_CENTER
- True
-
-
- 3
- GTK_FILL
-
- 10
-
-
-
-
- True
- True
- <span foreground='red'><b>MISSING KEYWORD</b></span>
- True
-
3
2
@@ -617,51 +562,90 @@
-
+
True
- 1
- True
+ True
+ <span foreground='red'><b>MISSING KEYWORD</b></span>
+ True
+
+
+ 3
+ 2
+ 3
+ GTK_FILL
+
+
+
+
+ True
+ GTK_JUSTIFY_CENTER
+ True
+
+
+ 3
+ GTK_FILL
+
+ 10
+
+
+
+
+ True
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ 5
-
+
True
- True
- Installed
- 0
- True
-
+ True
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ GTK_POLICY_NEVER
+ GTK_POLICY_AUTOMATIC
+
+
+ True
+ True
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ True
+ False
+
+
+
- False
+ False
-
+
True
- True
- Masked
- 0
- True
-
+ False
+ GTK_POLICY_AUTOMATIC
+ GTK_POLICY_AUTOMATIC
+
+
+ True
+
+
- False
1
-
-
- True
- True
- Testing
- 0
- True
-
-
-
- False
- 2
-
-
+
+
+ 3
+ 3
+ 4
+ 5
+ 5
+
+
+
+
+ True
+ True
+ <b>Installed, but not in portage anymore</b>
+ True
3
@@ -670,6 +654,22 @@
GTK_FILL
+
+
+ True
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+
+
+
+
+
+ 3
+ 1
+ 2
+ GTK_EXPAND
+
+
+
False
@@ -1147,189 +1147,189 @@
-
+
True
+ 0
+ 5
+ <u><i>Masking Keywords</i></u>
+ True
+ True
- 1
- 2
- 3
- 4
+ 7
+ 8
+ 5
-
+
True
0
- File name to use, if package.use is a directory:
+ 5
+ <u><i>Testing Keywords</i></u>
+ True
True
- 3
- 4
+ 4
+ 5
+ 5
-
+
True
- Add only exact version to package.use
- 0
- True
+ 0
+ 5
+ <u><i>Use-Flags</i></u>
+ True
+ True
+
+
+ 1
+ 2
+ 6
+
+
+
+
+ True
+
+
+ True
+ 0
+ GTK_SHADOW_OUT
+
+
+ True
+ 0
+ <u>You may use the following placeholders:</u>
+
+<i>$(cat)</i>: category
+<i>$(pkg)</i>: package name
+<i>$(cat-1)/$(cat-2)</i>: first/second part of the category
+ True
+
+
+
+
+
+ label_item
+
+
+
+
2
- 2
- 3
-
+
True
- Add only exact version to package.keywords
+ Add only exact version to package.mask/package.unmask
0
True
2
- 5
- 6
+ 8
+ 9
-
+
True
0
- File name to use, if package.keywords is a directory:
+ File name to use, if package.mask/package.unmask is a directory:
True
- 6
- 7
+ 9
+ 10
-
+
True
1
2
- 6
- 7
+ 9
+ 10
-
+
True
1
2
- 9
- 10
+ 6
+ 7
-
+
True
0
- File name to use, if package.mask/package.unmask is a directory:
+ File name to use, if package.keywords is a directory:
True
- 9
- 10
+ 6
+ 7
-
+
True
- Add only exact version to package.mask/package.unmask
+ Add only exact version to package.keywords
0
True
2
- 8
- 9
+ 5
+ 6
-
+
True
-
-
- True
- 0
- GTK_SHADOW_OUT
-
-
- True
- 0
- <u>You may use the following placeholders:</u>
-
-<i>$(cat)</i>: category
-<i>$(pkg)</i>: package name
-<i>$(cat-1)/$(cat-2)</i>: first/second part of the category
- True
-
-
-
-
-
- label_item
-
-
-
-
+ Add only exact version to package.use
+ 0
+ True
2
+ 2
+ 3
-
- True
- 0
- 5
- <u><i>Use-Flags</i></u>
- True
- True
-
-
- 1
- 2
- 6
-
-
-
-
+
True
0
- 5
- <u><i>Testing Keywords</i></u>
- True
+ File name to use, if package.use is a directory:
True
- 4
- 5
- 5
+ 3
+ 4
-
+
True
- 0
- 5
- <u><i>Masking Keywords</i></u>
- True
- True
- 7
- 8
- 5
+ 1
+ 2
+ 3
+ 4
diff --git a/portato/helper.py b/portato/helper.py
index 754f566..cb3289c 100644
--- a/portato/helper.py
+++ b/portato/helper.py
@@ -14,7 +14,7 @@
Some nice functions used in the program.
"""
-import os, signal, logging
+import os, signal, logging, grp
debug = logging.getLogger("portatoLogger").debug
info = logging.getLogger("portatoLogger").info
@@ -43,21 +43,6 @@ def send_signal_to_group (sig):
pgid = os.getpgrp()
os.killpg(pgid, sig)
-def am_i_root ():
- """Returns True if the current user is root, False otherwise.
- @rtype: boolean"""
-
- from plugin import hook
-
- @hook("am_i_root")
- def __am_i_root():
- if os.getuid() == 0:
- return True
- else:
- return False
-
- return __am_i_root()
-
def flatten (listOfLists):
"""Flattens the given list of lists.
diff --git a/portato/plistener.py b/portato/plistener.py
new file mode 100644
index 0000000..29054b2
--- /dev/null
+++ b/portato/plistener.py
@@ -0,0 +1,127 @@
+# -*- coding: utf-8 -*-
+#
+# File: portato/gui/gtk/plistener.py
+# This file is part of the Portato-Project, a graphical portage-frontend.
+#
+# Copyright (C) 2007 René 'Necoro' Neumann
+# This is free software. You may redistribute copies of it under the terms of
+# the GNU General Public License version 2.
+# There is NO WARRANTY, to the extent permitted by law.
+#
+# Written by René 'Necoro' Neumann
+
+import socket, os
+from subprocess import Popen
+from gettext import lgettext as _
+
+try:
+ import pynotify
+except ImportError:
+ pynotify = None
+
+from constants import SOCKET, APP
+from helper import debug, warning
+
+class PListener (object):
+ """This class handles the communication between the "listener" and the GUI.
+ This listener starts programs as the user while the GUI runs as root.
+
+ @ivar _recv: listener socket
+ @type _recv: socket.socket
+ @ivar _send: sender socket
+ @type _send: socket.socket"""
+
+ def set_recv (self):
+ self._recv = socket.socket(socket.AF_UNIX)
+
+ try:
+ self._recv.bind(SOCKET)
+ except socket.error, e:
+ if int(e[0]) == 98: # already existing - delete
+ os.unlink(SOCKET)
+ self._recv.bind(SOCKET)
+ else:
+ raise
+
+ self._recv.listen(1)
+ con, addr = self._recv.accept()
+
+ while True:
+ try:
+ len = con.recv(4)
+ string = con.recv(int(len))
+
+ data = string.split("\0")
+ debug(data)
+
+ if data[0] == "notify":
+ self.do_notify(*data[1:])
+ elif data[0] == "cmd":
+ self.do_cmd(data[1:])
+ elif data[0] == "close":
+ break
+ except KeyboardInterrupt:
+ pass
+
+ con.close()
+ self._recv.close()
+
+ def do_cmd (self, cmdlist):
+ """Starts a command as the user.
+
+ @param cmdlist: list of command (options)
+ @type cmdlist: string[]"""
+
+ Popen(cmdlist)
+
+ def do_notify(self, base, descr, icon, urgency):
+ """Displays a notify.
+ This will do nothing if pynotify is not present and/or root is running the listener."""
+
+ if pynotify and not os.getuid == 0:
+ if not pynotify.is_initted():
+ pynotify.init(APP)
+
+ n = pynotify.Notification(base, descr, icon)
+ n.set_urgency(int(urgency))
+ n.show()
+
+ def set_send (self):
+ self._send = socket.socket(socket.AF_UNIX)
+ try:
+ self._send.connect(SOCKET)
+ except socket.error, e:
+ if e[0] in [111, 2]: # can't connect
+ warning(_("Listener has not been started."))
+ self._send = None
+ else:
+ raise
+
+ def __send (self, string):
+ self._send.sendall("%4d" % len(string))
+ self._send.sendall(string)
+
+ def send_notify (self, base = "", descr = "", icon = "", urgency = None):
+ if self._send is None:
+ self.do_notify(base, descr, icon, urgency)
+ else:
+ string = "\0".join(["notify", base, descr, icon])
+
+ if urgency is not None:
+ string += "\0%d" % urgency
+ else:
+ string += "\0"
+
+ self.__send(string)
+
+ def send_cmd (self, cmdlist):
+ if self._send is None:
+ self.do_cmd(cmdlist)
+ else:
+ self.__send("\0".join(["cmd"] +cmdlist))
+
+ def close (self):
+ if self._send is not None:
+ self.__send("close")
+ self._send.close()
+ os.unlink(SOCKET)
diff --git a/portato/plugin.py b/portato/plugin.py
index 3b065b9..baa5d0c 100644
--- a/portato/plugin.py
+++ b/portato/plugin.py
@@ -133,6 +133,9 @@ class Hook:
@param connects: the list of 's
@type connects: NodeList"""
+ if not connects: # no connects - assume "before" connect
+ self.connects.append(Connect(self, "before", None))
+
for c in connects:
type = c.getAttribute("type")
if type == '':
diff --git a/portato/plugins/etc_proposals.py b/portato/plugins/etc_proposals.py
index 81370e0..f094599 100644
--- a/portato/plugins/etc_proposals.py
+++ b/portato/plugins/etc_proposals.py
@@ -13,6 +13,7 @@
from portato.helper import *
from portato.backend import system
+import os
from subprocess import Popen
from gettext import lgettext as _
from etcproposals.etcproposals_lib import EtcProposals, __version__
@@ -64,7 +65,7 @@ def etc_prop (*args, **kwargs):
error(_("Cannot start etc-proposals. No graphical frontend installed!"))
def etc_prop_menu (*args, **kwargs):
- if am_i_root():
+ if os.getuid() == 0:
if float(__version__) < 1.1:
Popen(PROG)
else:
diff --git a/portato/plugins/noroot.py b/portato/plugins/noroot.py
deleted file mode 100644
index a28ef85..0000000
--- a/portato/plugins/noroot.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# File: portato/plugins/noroot.py
-# This file is part of the Portato-Project, a graphical portage-frontend.
-#
-# Copyright (C) 2007 René 'Necoro' Neumann
-# This is free software. You may redistribute copies of it under the terms of
-# the GNU General Public License version 2.
-# There is NO WARRANTY, to the extent permitted by law.
-#
-# Written by René 'Necoro' Neumann
-
-def i_am_root (*args):
- """Pretend we are root."""
- return True
diff --git a/portato/plugins/notify.py b/portato/plugins/notify.py
new file mode 100644
index 0000000..5e4a577
--- /dev/null
+++ b/portato/plugins/notify.py
@@ -0,0 +1,23 @@
+from gettext import lgettext as _
+import pynotify
+
+from portato import listener
+
+from portato.helper import warning, error, debug
+from portato.constants import APP_ICON, APP
+
+def notify (retcode, **kwargs):
+ if retcode is None:
+ warning(_("Notify called while process is still running!"))
+ else:
+ icon = APP_ICON
+ if retcode == 0:
+ text = "Emerge finished!"
+ descr = ""
+ urgency = pynotify.URGENCY_NORMAL
+ else:
+ text = "Emerge failed!"
+ descr = "Error Code: %d" % retcode
+ urgency = pynotify.URGENCY_CRITICAL
+
+ listener.send_notify(base = text, descr = descr, icon = icon, urgency = urgency)
--
cgit v1.2.3-54-g00ecf