diff options
Diffstat (limited to '')
-rw-r--r-- | portato.desktop | 2 | ||||
-rwxr-xr-x | portato.py | 35 | ||||
-rw-r--r-- | portato/__init__.py | 3 | ||||
-rw-r--r-- | portato/constants.py | 7 | ||||
-rw-r--r-- | portato/gui/gtk/__init__.py | 3 | ||||
-rw-r--r-- | portato/gui/gtk/windows.py | 111 | ||||
-rw-r--r-- | portato/gui/templates/portato.glade | 420 | ||||
-rw-r--r-- | portato/helper.py | 17 | ||||
-rw-r--r-- | portato/plistener.py | 127 | ||||
-rw-r--r-- | portato/plugin.py | 3 | ||||
-rw-r--r-- | portato/plugins/etc_proposals.py | 3 | ||||
-rw-r--r-- | portato/plugins/noroot.py | 15 | ||||
-rw-r--r-- | portato/plugins/notify.py | 23 |
13 files changed, 460 insertions, 309 deletions
diff --git a/portato.desktop b/portato.desktop index e65eaa8..693235e 100644 --- a/portato.desktop +++ b/portato.desktop @@ -1,7 +1,7 @@ [Desktop Entry] Name=Portato Icon=portato-icon -Exec=gksu -D "Portato (GTK)" -u root portato gtk +Exec=portato StartupNotify=true Type=Application Categories=Application;System;PackageManager @@ -12,9 +12,11 @@ # # Written by René 'Necoro' Neumann <necoro@necoro.net> -from portato.constants import VERSION, FRONTENDS, STD_FRONTEND, XSD_LOCATION, LOCALE_DIR, APP +from portato import listener +from portato.constants import VERSION, FRONTENDS, STD_FRONTEND, XSD_LOCATION, LOCALE_DIR, APP, SU_COMMAND from optparse import OptionParser -import sys, os +from subprocess import call +import sys, os, socket import gettext, locale def get_frontend_list (): @@ -46,6 +48,9 @@ def main (): parser.add_option("-x", "--validate", action = "store", dest = "validate", metavar="PLUGIN", help = _("validates the given plugin xml instead of launching Portato")) + parser.add_option("-L", "--no-listener", action = "store_true", dest = "nolistener", default = False, + help = _("do not start listener")) + # run parser (options, args) = parser.parse_args() @@ -83,8 +88,32 @@ def main (): else: print _("Validation succeeded.") return - else: + elif options.nolistener: + try: + # move this process into a new process group + # this is to be able to kill emerge et al w/o killing ourselves :) + os.setsid() + except OSError: + pass + listener.set_send() run() + else: # start listener and start us again in root modus + if os.fork() == 0: + listener.set_recv() + else: + additional = [] + if options.check: + additional.append("-c") + if options.frontend: + additional.extend(["-f", options.frontend]) + + try: + if os.getuid() == 0: + call([SU_COMMAND, "%s --no-listener %s" % (sys.argv[0], " ".join(additional))], env = os.environ) + else: + call([sys.argv[0], "--no-listener"]+additional, env = os.environ) + except KeyboardInterrupt: + pass if __name__ == "__main__": main() 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,109 +450,54 @@ <property name="n_rows">5</property> <property name="n_columns">3</property> <child> - <widget class="GtkHBox" id="pkgLinkBox"> + <widget class="GtkHBox" id="checkHB"> <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="spacing">1</property> + <property name="homogeneous">True</property> <child> - <placeholder/> + <widget class="GtkCheckButton" id="installedCheck"> + <property name="visible">True</property> + <property name="no_show_all">True</property> + <property name="label" translatable="yes">Installed</property> + <property name="response_id">0</property> + <property name="draw_indicator">True</property> + <signal name="button_press_event" handler="cb_button_pressed"/> + </widget> + <packing> + <property name="fill">False</property> + </packing> </child> - </widget> - <packing> - <property name="right_attach">3</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options">GTK_EXPAND</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="notInSysLabel"> - <property name="visible">True</property> - <property name="no_show_all">True</property> - <property name="label" translatable="yes"><b>Installed, but not in portage anymore</b></property> - <property name="use_markup">True</property> - </widget> - <packing> - <property name="right_attach">3</property> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - <property name="y_options">GTK_FILL</property> - </packing> - </child> - <child> - <widget class="GtkHBox" id="hbox2"> - <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="spacing">5</property> <child> - <widget class="GtkScrolledWindow" id="versionListScroll"> + <widget class="GtkCheckButton" id="maskedCheck"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="hscrollbar_policy">GTK_POLICY_NEVER</property> - <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> - <child> - <widget class="GtkTreeView" id="versionList"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="headers_clickable">True</property> - <property name="show_expanders">False</property> - <signal name="cursor_changed" handler="cb_vers_list_changed"/> - </widget> - </child> + <property name="no_show_all">True</property> + <property name="label" translatable="yes">Masked</property> + <property name="response_id">0</property> + <property name="draw_indicator">True</property> + <signal name="toggled" handler="cb_masked_toggled"/> </widget> <packing> - <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> </packing> </child> <child> - <widget class="GtkScrolledWindow" id="useListScroll"> + <widget class="GtkCheckButton" id="testingCheck"> <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> - <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> - <child> - <widget class="GtkTreeView" id="useList"> - <property name="visible">True</property> - </widget> - </child> + <property name="no_show_all">True</property> + <property name="label" translatable="yes">Testing</property> + <property name="response_id">0</property> + <property name="draw_indicator">True</property> + <signal name="toggled" handler="cb_testing_toggled"/> </widget> <packing> - <property name="position">1</property> + <property name="fill">False</property> + <property name="position">2</property> </packing> </child> </widget> <packing> <property name="right_attach">3</property> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> - <property name="x_padding">5</property> - <property name="y_padding">5</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="descLabel"> - <property name="visible">True</property> - <property name="justify">GTK_JUSTIFY_CENTER</property> - <property name="wrap">True</property> - </widget> - <packing> - <property name="right_attach">3</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - <property name="y_padding">10</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="missingLabel"> - <property name="visible">True</property> - <property name="no_show_all">True</property> - <property name="label" translatable="yes"><span foreground='red'><b>MISSING KEYWORD</b></span></property> - <property name="use_markup">True</property> - </widget> - <packing> - <property name="right_attach">3</property> <property name="top_attach">2</property> <property name="bottom_attach">3</property> <property name="y_options">GTK_FILL</property> @@ -617,51 +562,90 @@ </packing> </child> <child> - <widget class="GtkHBox" id="checkHB"> + <widget class="GtkLabel" id="missingLabel"> <property name="visible">True</property> - <property name="spacing">1</property> - <property name="homogeneous">True</property> + <property name="no_show_all">True</property> + <property name="label" translatable="yes"><span foreground='red'><b>MISSING KEYWORD</b></span></property> + <property name="use_markup">True</property> + </widget> + <packing> + <property name="right_attach">3</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="descLabel"> + <property name="visible">True</property> + <property name="justify">GTK_JUSTIFY_CENTER</property> + <property name="wrap">True</property> + </widget> + <packing> + <property name="right_attach">3</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + <property name="y_padding">10</property> + </packing> + </child> + <child> + <widget class="GtkHBox" id="hbox2"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="spacing">5</property> <child> - <widget class="GtkCheckButton" id="installedCheck"> + <widget class="GtkScrolledWindow" id="versionListScroll"> <property name="visible">True</property> - <property name="no_show_all">True</property> - <property name="label" translatable="yes">Installed</property> - <property name="response_id">0</property> - <property name="draw_indicator">True</property> - <signal name="button_press_event" handler="cb_button_pressed"/> + <property name="can_focus">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="hscrollbar_policy">GTK_POLICY_NEVER</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <child> + <widget class="GtkTreeView" id="versionList"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="headers_clickable">True</property> + <property name="show_expanders">False</property> + <signal name="cursor_changed" handler="cb_vers_list_changed"/> + </widget> + </child> </widget> <packing> - <property name="fill">False</property> + <property name="expand">False</property> </packing> </child> <child> - <widget class="GtkCheckButton" id="maskedCheck"> + <widget class="GtkScrolledWindow" id="useListScroll"> <property name="visible">True</property> - <property name="no_show_all">True</property> - <property name="label" translatable="yes">Masked</property> - <property name="response_id">0</property> - <property name="draw_indicator">True</property> - <signal name="toggled" handler="cb_masked_toggled"/> + <property name="can_focus">False</property> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <child> + <widget class="GtkTreeView" id="useList"> + <property name="visible">True</property> + </widget> + </child> </widget> <packing> - <property name="fill">False</property> <property name="position">1</property> </packing> </child> - <child> - <widget class="GtkCheckButton" id="testingCheck"> - <property name="visible">True</property> - <property name="no_show_all">True</property> - <property name="label" translatable="yes">Testing</property> - <property name="response_id">0</property> - <property name="draw_indicator">True</property> - <signal name="toggled" handler="cb_testing_toggled"/> - </widget> - <packing> - <property name="fill">False</property> - <property name="position">2</property> - </packing> - </child> + </widget> + <packing> + <property name="right_attach">3</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> + <property name="x_padding">5</property> + <property name="y_padding">5</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="notInSysLabel"> + <property name="visible">True</property> + <property name="no_show_all">True</property> + <property name="label" translatable="yes"><b>Installed, but not in portage anymore</b></property> + <property name="use_markup">True</property> </widget> <packing> <property name="right_attach">3</property> @@ -670,6 +654,22 @@ <property name="y_options">GTK_FILL</property> </packing> </child> + <child> + <widget class="GtkHBox" id="pkgLinkBox"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <child> + <placeholder/> + </child> + </widget> + <packing> + <property name="right_attach">3</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">GTK_EXPAND</property> + <property name="y_options"></property> + </packing> + </child> </widget> <packing> <property name="tab_expand">False</property> @@ -1147,189 +1147,189 @@ <placeholder/> </child> <child> - <widget class="GtkEntry" id="useFileEdit"> + <widget class="GtkLabel" id="maskLabel"> <property name="visible">True</property> + <property name="xalign">0</property> + <property name="xpad">5</property> + <property name="label" translatable="yes"><u><i>Masking Keywords</i></u></property> + <property name="use_markup">True</property> + <property name="single_line_mode">True</property> </widget> <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> + <property name="top_attach">7</property> + <property name="bottom_attach">8</property> + <property name="y_padding">5</property> </packing> </child> <child> - <widget class="GtkLabel" id="useEditLabel"> + <widget class="GtkLabel" id="testLabel"> <property name="visible">True</property> <property name="xalign">0</property> - <property name="label" translatable="yes">File name to use, if package.use is a directory: </property> + <property name="xpad">5</property> + <property name="label" translatable="yes"><u><i>Testing Keywords</i></u></property> + <property name="use_markup">True</property> <property name="single_line_mode">True</property> </widget> <packing> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> + <property name="y_padding">5</property> </packing> </child> <child> - <widget class="GtkCheckButton" id="usePerVersionCheck"> + <widget class="GtkLabel" id="useLabel"> <property name="visible">True</property> - <property name="label" translatable="yes">Add only exact version to package.use</property> - <property name="response_id">0</property> - <property name="draw_indicator">True</property> + <property name="xalign">0</property> + <property name="xpad">5</property> + <property name="label" translatable="yes"><u><i>Use-Flags</i></u></property> + <property name="use_markup">True</property> + <property name="single_line_mode">True</property> + </widget> + <packing> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_padding">6</property> + </packing> + </child> + <child> + <widget class="GtkEventBox" id="hintEB"> + <property name="visible">True</property> + <child> + <widget class="GtkFrame" id="hintFrame"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="shadow_type">GTK_SHADOW_OUT</property> + <child> + <widget class="GtkLabel" id="hintLabel"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes"><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</property> + <property name="use_markup">True</property> + </widget> + </child> + <child> + <placeholder/> + <packing> + <property name="type">label_item</property> + </packing> + </child> + </widget> + </child> </widget> <packing> <property name="right_attach">2</property> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> </packing> </child> <child> - <widget class="GtkCheckButton" id="testPerVersionCheck"> + <widget class="GtkCheckButton" id="maskPerVersionCheck"> <property name="visible">True</property> - <property name="label" translatable="yes">Add only exact version to package.keywords</property> + <property name="label" translatable="yes">Add only exact version to package.mask/package.unmask</property> <property name="response_id">0</property> <property name="draw_indicator">True</property> </widget> <packing> <property name="right_attach">2</property> - <property name="top_attach">5</property> - <property name="bottom_attach">6</property> + <property name="top_attach">8</property> + <property name="bottom_attach">9</property> </packing> </child> <child> - <widget class="GtkLabel" id="testEditLabel"> + <widget class="GtkLabel" id="maskEditLabel"> <property name="visible">True</property> <property name="xalign">0</property> - <property name="label" translatable="yes">File name to use, if package.keywords is a directory: </property> + <property name="label" translatable="yes">File name to use, if package.mask/package.unmask is a directory: </property> <property name="single_line_mode">True</property> </widget> <packing> - <property name="top_attach">6</property> - <property name="bottom_attach">7</property> + <property name="top_attach">9</property> + <property name="bottom_attach">10</property> </packing> </child> <child> - <widget class="GtkEntry" id="testFileEdit"> + <widget class="GtkEntry" id="maskFileEdit"> <property name="visible">True</property> </widget> <packing> <property name="left_attach">1</property> <property name="right_attach">2</property> - <property name="top_attach">6</property> - <property name="bottom_attach">7</property> + <property name="top_attach">9</property> + <property name="bottom_attach">10</property> </packing> </child> <child> - <widget class="GtkEntry" id="maskFileEdit"> + <widget class="GtkEntry" id="testFileEdit"> <property name="visible">True</property> </widget> <packing> <property name="left_attach">1</property> <property name="right_attach">2</property> - <property name="top_attach">9</property> - <property name="bottom_attach">10</property> + <property name="top_attach">6</property> + <property name="bottom_attach">7</property> </packing> </child> <child> - <widget class="GtkLabel" id="maskEditLabel"> + <widget class="GtkLabel" id="testEditLabel"> <property name="visible">True</property> <property name="xalign">0</property> - <property name="label" translatable="yes">File name to use, if package.mask/package.unmask is a directory: </property> + <property name="label" translatable="yes">File name to use, if package.keywords is a directory: </property> <property name="single_line_mode">True</property> </widget> <packing> - <property name="top_attach">9</property> - <property name="bottom_attach">10</property> + <property name="top_attach">6</property> + <property name="bottom_attach">7</property> </packing> </child> <child> - <widget class="GtkCheckButton" id="maskPerVersionCheck"> + <widget class="GtkCheckButton" id="testPerVersionCheck"> <property name="visible">True</property> - <property name="label" translatable="yes">Add only exact version to package.mask/package.unmask</property> + <property name="label" translatable="yes">Add only exact version to package.keywords</property> <property name="response_id">0</property> <property name="draw_indicator">True</property> </widget> <packing> <property name="right_attach">2</property> - <property name="top_attach">8</property> - <property name="bottom_attach">9</property> + <property name="top_attach">5</property> + <property name="bottom_attach">6</property> </packing> </child> <child> - <widget class="GtkEventBox" id="hintEB"> + <widget class="GtkCheckButton" id="usePerVersionCheck"> <property name="visible">True</property> - <child> - <widget class="GtkFrame" id="hintFrame"> - <property name="visible">True</property> - <property name="label_xalign">0</property> - <property name="shadow_type">GTK_SHADOW_OUT</property> - <child> - <widget class="GtkLabel" id="hintLabel"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes"><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</property> - <property name="use_markup">True</property> - </widget> - </child> - <child> - <placeholder/> - <packing> - <property name="type">label_item</property> - </packing> - </child> - </widget> - </child> + <property name="label" translatable="yes">Add only exact version to package.use</property> + <property name="response_id">0</property> + <property name="draw_indicator">True</property> </widget> <packing> <property name="right_attach">2</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> </packing> </child> <child> - <widget class="GtkLabel" id="useLabel"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">5</property> - <property name="label" translatable="yes"><u><i>Use-Flags</i></u></property> - <property name="use_markup">True</property> - <property name="single_line_mode">True</property> - </widget> - <packing> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="y_padding">6</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="testLabel"> + <widget class="GtkLabel" id="useEditLabel"> <property name="visible">True</property> <property name="xalign">0</property> - <property name="xpad">5</property> - <property name="label" translatable="yes"><u><i>Testing Keywords</i></u></property> - <property name="use_markup">True</property> + <property name="label" translatable="yes">File name to use, if package.use is a directory: </property> <property name="single_line_mode">True</property> </widget> <packing> - <property name="top_attach">4</property> - <property name="bottom_attach">5</property> - <property name="y_padding">5</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> </packing> </child> <child> - <widget class="GtkLabel" id="maskLabel"> + <widget class="GtkEntry" id="useFileEdit"> <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">5</property> - <property name="label" translatable="yes"><u><i>Masking Keywords</i></u></property> - <property name="use_markup">True</property> - <property name="single_line_mode">True</property> </widget> <packing> - <property name="top_attach">7</property> - <property name="bottom_attach">8</property> - <property name="y_padding">5</property> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> </packing> </child> </widget> 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 <necoro@necoro.net> + +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 <connect>'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 <necoro@necoro.net> - -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) |