diff options
-rw-r--r-- | doc/Changelog | 2 | ||||
-rw-r--r-- | doc/Hooks | 7 | ||||
-rw-r--r-- | doc/Howto_Write_Plugins | 1 | ||||
-rw-r--r-- | doc/TODO | 2 | ||||
-rw-r--r-- | i18n/de_DE.po | 238 | ||||
-rw-r--r-- | i18n/messages.pot | 198 | ||||
-rw-r--r-- | plugin.xsd | 2 | ||||
-rw-r--r-- | plugins/notify.xml (renamed from plugins/noroot.xml) | 12 | ||||
-rw-r--r-- | plugins/resume_loop.xml | 4 | ||||
-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 |
22 files changed, 704 insertions, 531 deletions
diff --git a/doc/Changelog b/doc/Changelog index 0893e48..fa48774 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -4,6 +4,8 @@ next: - new threading model for the emerge process - minor enhancements - added splash screen +- added notifies +- added listener / launch gksu/kdesu by ourselves 0.8.1: - bugfixes @@ -1,13 +1,6 @@ List of hooks currently being supported by Portato ================================================== -am_i_root ---------- -Called: When checking whether the current user is root (ie. uid == 0). -Parameters: None -Return if override: Boolean signaling whether we are root. - - emerge: ------- Called: When emerge or every other command given by e.g. the synccmd preference is being called. diff --git a/doc/Howto_Write_Plugins b/doc/Howto_Write_Plugins index 6c4f97f..9b0e375 100644 --- a/doc/Howto_Write_Plugins +++ b/doc/Howto_Write_Plugins @@ -42,6 +42,7 @@ Sample XML Notes: - If you want to specify a dependency plugin the connect tag has to be like: <connect type = "after"> The other plugin we depend on </connect>. +- The "connect"-tag can be omitted. It then defaults to "<connect type='before' />". - It is possible of course to have more than one "hook" tag. - The options tag is optional. For a complete list of options, see below. @@ -26,6 +26,8 @@ Main Point: user preferences: - window size / location - colors and font sizes +- rotating systray icon + GTK: ---- - make oneshot better diff --git a/i18n/de_DE.po b/i18n/de_DE.po index f61b737..936b13a 100644 --- a/i18n/de_DE.po +++ b/i18n/de_DE.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Portato\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2007-08-09 20:20-0800\n" +"PO-Revision-Date: 2007-08-11 22:13-0800\n" "Last-Translator: René 'Necoro' Neumann <necoro@necoro.net>\n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -30,18 +30,18 @@ msgid "gtk-quit" msgstr "" #: portato/gui/templates/portato.glade:81 -#: portato/gui/templates/portato.glade:569 +#: portato/gui/templates/portato.glade:514 msgid "_Emerge" msgstr "_Emerge" #: portato/gui/templates/portato.glade:89 #: portato/gui/templates/portato.glade:719 -#: portato/gui/gtk/windows.py:690 +#: portato/gui/gtk/windows.py:691 msgid "E_merge" msgstr "E_merge" #: portato/gui/templates/portato.glade:104 -#: portato/gui/templates/portato.glade:578 +#: portato/gui/templates/portato.glade:523 #: portato/gui/templates/portato.glade:728 msgid "_Unmerge" msgstr "_Unmerge" @@ -112,47 +112,47 @@ msgstr "Zeige _Log" msgid "gtk-find" msgstr "" -#: portato/gui/templates/portato.glade:472 -msgid "<b>Installed, but not in portage anymore</b>" -msgstr "<b>Installiert, aber nicht mehr im Portage-Tree vorhanden</b>" - -#: portato/gui/templates/portato.glade:551 -msgid "<span foreground='red'><b>MISSING KEYWORD</b></span>" -msgstr "<span foreground='red'><b>FEHLENDES KEYWORD</b></span>" - -#: portato/gui/templates/portato.glade:590 -msgid "Re_vert" -msgstr "_Wiederherstellen" - -#: portato/gui/templates/portato.glade:602 -msgid "E_build" -msgstr "E_build" - -#: portato/gui/templates/portato.glade:628 +#: portato/gui/templates/portato.glade:461 msgid "Installed" msgstr "Installiert" -#: portato/gui/templates/portato.glade:641 -#: portato/gui/gtk/windows.py:667 -#: portato/gui/gtk/windows.py:670 -#: portato/gui/gtk/windows.py:673 -#: portato/gui/gtk/windows.py:778 -#: portato/gui/gtk/windows.py:781 -#: portato/gui/gtk/windows.py:788 -#: portato/gui/gtk/windows.py:792 +#: portato/gui/templates/portato.glade:474 +#: portato/gui/gtk/windows.py:668 +#: portato/gui/gtk/windows.py:671 +#: portato/gui/gtk/windows.py:674 +#: portato/gui/gtk/windows.py:773 +#: portato/gui/gtk/windows.py:776 +#: portato/gui/gtk/windows.py:783 +#: portato/gui/gtk/windows.py:787 msgid "Masked" msgstr "Masked" -#: portato/gui/templates/portato.glade:655 -#: portato/gui/gtk/windows.py:680 -#: portato/gui/gtk/windows.py:683 +#: portato/gui/templates/portato.glade:488 +#: portato/gui/gtk/windows.py:681 +#: portato/gui/gtk/windows.py:684 +#: portato/gui/gtk/windows.py:745 #: portato/gui/gtk/windows.py:750 -#: portato/gui/gtk/windows.py:755 msgid "Testing" msgstr "Testing" +#: portato/gui/templates/portato.glade:535 +msgid "Re_vert" +msgstr "_Wiederherstellen" + +#: portato/gui/templates/portato.glade:547 +msgid "E_build" +msgstr "E_build" + +#: portato/gui/templates/portato.glade:568 +msgid "<span foreground='red'><b>MISSING KEYWORD</b></span>" +msgstr "<span foreground='red'><b>FEHLENDES KEYWORD</b></span>" + +#: portato/gui/templates/portato.glade:647 +msgid "<b>Installed, but not in portage anymore</b>" +msgstr "<b>Installiert, aber nicht mehr im Portage-Tree vorhanden</b>" + #: portato/gui/templates/portato.glade:682 -#: portato/gui/gtk/windows.py:127 +#: portato/gui/gtk/windows.py:128 msgid "Package" msgstr "Paket" @@ -161,12 +161,12 @@ msgid "_Remove" msgstr "_Löschen" #: portato/gui/templates/portato.glade:777 -#: portato/gui/gtk/windows.py:1003 +#: portato/gui/gtk/windows.py:998 msgid "Queue" msgstr "Queue" #: portato/gui/templates/portato.glade:805 -#: portato/gui/gtk/windows.py:1100 +#: portato/gui/gtk/windows.py:1095 msgid "Console" msgstr "Konsole" @@ -220,31 +220,19 @@ msgstr "Sync-Befehl: " msgid "<b>Sync Options</b>" msgstr "<b>Sync Optionen</b>" -#: portato/gui/templates/portato.glade:1164 -msgid "File name to use, if package.use is a directory: " -msgstr "Zu benutzender Dateiname, wenn package.use ein Verzeichnis ist:" - -#: portato/gui/templates/portato.glade:1175 -msgid "Add only exact version to package.use" -msgstr "Füge nur die exakte Paketversion zu package.keywords hinzu" - -#: portato/gui/templates/portato.glade:1188 -msgid "Add only exact version to package.keywords" -msgstr "Füge nur die exakte Paketversion zu package.keywords hinzu" - -#: portato/gui/templates/portato.glade:1202 -msgid "File name to use, if package.keywords is a directory: " -msgstr "Zu benutzender Dateiname, wenn package.keywords ein Verzeichnis ist:" +#: portato/gui/templates/portato.glade:1154 +msgid "<u><i>Masking Keywords</i></u>" +msgstr "<u><i>Masking Keywords</i></u>" -#: portato/gui/templates/portato.glade:1236 -msgid "File name to use, if package.mask/package.unmask is a directory: " -msgstr "Zu benutzender Dateiname, wenn package.mask/package.unmask ein Verzeichnis ist:" +#: portato/gui/templates/portato.glade:1169 +msgid "<u><i>Testing Keywords</i></u>" +msgstr "<u><i>Testing Keywords</i></u>" -#: portato/gui/templates/portato.glade:1247 -msgid "Add only exact version to package.mask/package.unmask" -msgstr "Füge nur die exakte Paketversion zu package.mask/package.unmask hinzu" +#: portato/gui/templates/portato.glade:1184 +msgid "<u><i>Use-Flags</i></u>" +msgstr "<u><i>Use-Flags</i></u>" -#: portato/gui/templates/portato.glade:1269 +#: portato/gui/templates/portato.glade:1206 msgid "" "<u>You may use the following placeholders:</u>\n" "\n" @@ -258,17 +246,29 @@ msgstr "" "<i>$(pkg)</i>: Paketname\n" "<i>$(cat-1)/$(cat-2)</i>: erster/zweiter Teil der Kategorie" -#: portato/gui/templates/portato.glade:1295 -msgid "<u><i>Use-Flags</i></u>" -msgstr "<u><i>Use-Flags</i></u>" +#: portato/gui/templates/portato.glade:1230 +msgid "Add only exact version to package.mask/package.unmask" +msgstr "Füge nur die exakte Paketversion zu package.mask/package.unmask hinzu" -#: portato/gui/templates/portato.glade:1310 -msgid "<u><i>Testing Keywords</i></u>" -msgstr "<u><i>Testing Keywords</i></u>" +#: portato/gui/templates/portato.glade:1244 +msgid "File name to use, if package.mask/package.unmask is a directory: " +msgstr "Zu benutzender Dateiname, wenn package.mask/package.unmask ein Verzeichnis ist:" -#: portato/gui/templates/portato.glade:1325 -msgid "<u><i>Masking Keywords</i></u>" -msgstr "<u><i>Masking Keywords</i></u>" +#: portato/gui/templates/portato.glade:1278 +msgid "File name to use, if package.keywords is a directory: " +msgstr "Zu benutzender Dateiname, wenn package.keywords ein Verzeichnis ist:" + +#: portato/gui/templates/portato.glade:1289 +msgid "Add only exact version to package.keywords" +msgstr "Füge nur die exakte Paketversion zu package.keywords hinzu" + +#: portato/gui/templates/portato.glade:1302 +msgid "Add only exact version to package.use" +msgstr "Füge nur die exakte Paketversion zu package.keywords hinzu" + +#: portato/gui/templates/portato.glade:1316 +msgid "File name to use, if package.use is a directory: " +msgstr "Zu benutzender Dateiname, wenn package.use ein Verzeichnis ist:" #: portato/gui/templates/portato.glade:1342 msgid "<b>Use Flag and Keyword Options</b>" @@ -355,100 +355,104 @@ msgstr "Logs" msgid "Resume-loop called while process is still running!" msgstr "\"Resume-Loop\" aufgerufen, während Emerge noch lief. Bug!" -#: portato/plugins/etc_proposals.py:64 -#: portato/plugins/etc_proposals.py:76 +#: portato/plugins/etc_proposals.py:65 +#: portato/plugins/etc_proposals.py:77 msgid "Cannot start etc-proposals. No graphical frontend installed!" msgstr "Kann etc-proposals nicht starten. Kein grafisches Frontend installiert." -#: portato/plugins/etc_proposals.py:78 +#: portato/plugins/etc_proposals.py:79 msgid "Cannot start etc-proposals. Not root!" msgstr "Kann etc-proposals nicht starten. Nur root kann das!" -#: portato/gui/gtk/windows.py:72 +#: portato/plugins/notify.py:11 +msgid "Notify called while process is still running!" +msgstr "\"Notify\" aufgerufen, während Emerge noch lief." + +#: portato/gui/gtk/windows.py:73 msgid "Plugin" msgstr "Plugin" -#: portato/gui/gtk/windows.py:75 +#: portato/gui/gtk/windows.py:76 msgid "Authors" msgstr "Entwickler" -#: portato/gui/gtk/windows.py:80 -#: portato/gui/gtk/windows.py:126 -#: portato/gui/gtk/windows.py:541 +#: portato/gui/gtk/windows.py:81 +#: portato/gui/gtk/windows.py:127 +#: portato/gui/gtk/windows.py:542 msgid "Enabled" msgstr "Aktiviert" -#: portato/gui/gtk/windows.py:225 +#: portato/gui/gtk/windows.py:226 msgid "Results" msgstr "Ergebnisse" -#: portato/gui/gtk/windows.py:494 +#: portato/gui/gtk/windows.py:495 msgid "<no description>" msgstr "<keine Beschreibung>" -#: portato/gui/gtk/windows.py:523 +#: portato/gui/gtk/windows.py:524 msgid "This is an expanded use flag and cannot be selected" msgstr "Dies ist ein \"Expanded Use Flag\" und kann daher nicht ausgewählt werden." -#: portato/gui/gtk/windows.py:542 +#: portato/gui/gtk/windows.py:543 msgid "Flag" msgstr "Flag" -#: portato/gui/gtk/windows.py:543 +#: portato/gui/gtk/windows.py:544 msgid "Description" msgstr "Beschreibung" -#: portato/gui/gtk/windows.py:622 +#: portato/gui/gtk/windows.py:623 #, python-format msgid "Package could not be found: %s" msgstr "Paket konnte nicht gefunden werden: %s" -#: portato/gui/gtk/windows.py:693 +#: portato/gui/gtk/windows.py:694 msgid "Re_merge" msgstr "Re_merge" -#: portato/gui/gtk/windows.py:890 +#: portato/gui/gtk/windows.py:885 msgid "Creating Database" msgstr "Erstelle Datenbank" -#: portato/gui/gtk/windows.py:895 +#: portato/gui/gtk/windows.py:890 msgid "Loading Config" msgstr "Lade Konfiguration" -#: portato/gui/gtk/windows.py:906 +#: portato/gui/gtk/windows.py:901 msgid "Loading Plugins" msgstr "Lade Plugins" -#: portato/gui/gtk/windows.py:919 +#: portato/gui/gtk/windows.py:914 msgid "Finishing startup" msgstr "Erledige letzte Handgriffe :)" -#: portato/gui/gtk/windows.py:1006 +#: portato/gui/gtk/windows.py:1001 msgid "Options" msgstr "Optionen" -#: portato/gui/gtk/windows.py:1024 +#: portato/gui/gtk/windows.py:1019 msgid "Categories" msgstr "Kategorien" -#: portato/gui/gtk/windows.py:1039 +#: portato/gui/gtk/windows.py:1034 msgid "Packages" msgstr "Pakete" -#: portato/gui/gtk/windows.py:1102 +#: portato/gui/gtk/windows.py:1097 #, python-format msgid "Console (%(title)s)" msgstr "Konsole (%(title)s)" -#: portato/gui/gtk/windows.py:1154 +#: portato/gui/gtk/windows.py:1149 msgid "use flags" msgstr "Use Flags" -#: portato/gui/gtk/windows.py:1161 +#: portato/gui/gtk/windows.py:1156 msgid "masking keywords" msgstr "Masking Keywords" -#: portato/gui/gtk/__init__.py:20 +#: portato/gui/gtk/__init__.py:21 msgid "Loading Portage" msgstr "Lade Portage" @@ -587,90 +591,98 @@ msgstr "Konflikt beim Masking-Status: %s" msgid "Unrecognized line in configuration: %s" msgstr "Unbekannte Zeile in Konfiguration: %s" -#: portato/plugin.py:287 -#: portato/plugin.py:293 -#: portato/plugin.py:298 +#: portato/plugin.py:290 +#: portato/plugin.py:296 +#: portato/plugin.py:301 #, python-format msgid "%s cannot be imported." msgstr "%s kann nicht importiert werden." -#: portato/plugin.py:325 +#: portato/plugin.py:328 #, python-format msgid "Accessing hook '%(hook)s' of plugin '%(plugin)s' (before)." msgstr "Aufruf des Hooks '%(hook)s' vom Plugin '%(plugin)s'. (before)" -#: portato/plugin.py:329 +#: portato/plugin.py:332 #, python-format msgid "Overriding hook '%(hook)s' with plugin '%(plugin)s'." msgstr "Überschreibe den Hook '%(hook)s' mit Plugin '%(plugin)s'." -#: portato/plugin.py:336 +#: portato/plugin.py:339 #, python-format msgid "Accessing hook '%(hook)s' of plugin '%(plugin)s' (after)." msgstr "Aufruf des Hooks '%(hook)s' vom Plugin '%(plugin)s'. (after)" -#: portato/plugin.py:356 +#: portato/plugin.py:359 #, python-format msgid "Loading plugin '%s' failed. Invalid XML syntax." msgstr "Laden des Plugins '%s\" fehlgeschlagen: XML-Syntax-Fehler." -#: portato/plugin.py:359 +#: portato/plugin.py:362 #, python-format msgid "Loading plugin '%s' failed. Plugin does not comply with schema." msgstr "Laden des Plugins '%s\" fehlgeschlagen. Plugin erfüllt nicht das XML-Schema." -#: portato/plugin.py:388 +#: portato/plugin.py:391 #, python-format msgid "Plugin '%s' loaded." msgstr "Plugin '%s' geladen." -#: portato/plugin.py:391 +#: portato/plugin.py:394 #, python-format msgid "Loading plugin '%(plugin)s' failed: Could not import %(import)s" msgstr "Laden des Plugins '%(plugin)s\" fehlgeschlagen. Import von '%(import)s' nicht möglich." -#: portato/plugin.py:456 +#: portato/plugin.py:459 #, python-format msgid "For hook '%(hook)s' an override is already defined by plugin '%(plugin)s'!" msgstr "Das Plugin '%(plugin)s' definiert bereits einen \"Override\" fürr den Hook '%(hook)s'!" -#: portato.py:38 +#: portato/plistener.py:95 +msgid "Listener has not been started." +msgstr "Listener wurde nicht gestartet." + +#: portato.py:40 msgid "runs pychecker (should only be used by developers)" msgstr "Startet \"pychecker\". (Nur Entwickler sollten dies brauchen)." -#: portato.py:41 +#: portato.py:43 #, python-format msgid "the frontend to use - possible values are: %s [default: %%default]" msgstr "Das zu benutzende Frontend. Möglichkeiten: %s [Default: %%default]" -#: portato.py:44 +#: portato.py:46 msgid "opens the ebuild viewer instead of launching Portato" msgstr "Öffnet den Ebuild Viewer anstatt Portato zu starten" -#: portato.py:47 +#: portato.py:49 msgid "validates the given plugin xml instead of launching Portato" msgstr "Validiert die gegebene Plugin-XML. Startet nicht Portato." -#: portato.py:60 +#: portato.py:52 +msgid "do not start listener" +msgstr "Starte den Listener nicht." + +#: portato.py:65 #, python-format msgid "Unknown frontend '%(frontend)s'. Correct frontends are: %(list)s" msgstr "Unbekanntest Frontend '%(frontend)s'. Erlaubte Frontends sind: %(list)s" -#: portato.py:68 +#: portato.py:73 #, python-format msgid "'%(frontend)s' should be installed, but cannot be imported. This is definitly a bug. (%(error)s)" msgstr "'%(frontend)s' sollte installiert sein, aber das Einbinden schlug fehl. Das ist definitiv ein Bug. (%(error)s)" -#: portato.py:78 +#: portato.py:83 #, python-format msgid "Validation failed. XML syntax error: %s." msgstr "Validierung fehlgeschlagen. XML Syntax Fehler: %s." -#: portato.py:81 +#: portato.py:86 msgid "Validation failed. Does not comply with schema." msgstr "Validierung gegen das Schema fehlgeschlagen." -#: portato.py:84 +#: portato.py:89 msgid "Validation succeeded." msgstr "Validierung erfolgreich." diff --git a/i18n/messages.pot b/i18n/messages.pot index 272221d..b1efe83 100644 --- a/i18n/messages.pot +++ b/i18n/messages.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-08-09 20:17-0700\n" +"POT-Creation-Date: 2007-08-11 22:12-0700\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -34,17 +34,17 @@ msgid "gtk-quit" msgstr "" #: portato/gui/templates/portato.glade:81 -#: portato/gui/templates/portato.glade:569 +#: portato/gui/templates/portato.glade:514 msgid "_Emerge" msgstr "" #: portato/gui/templates/portato.glade:89 -#: portato/gui/templates/portato.glade:719 portato/gui/gtk/windows.py:690 +#: portato/gui/templates/portato.glade:719 portato/gui/gtk/windows.py:691 msgid "E_merge" msgstr "" #: portato/gui/templates/portato.glade:104 -#: portato/gui/templates/portato.glade:578 +#: portato/gui/templates/portato.glade:523 #: portato/gui/templates/portato.glade:728 msgid "_Unmerge" msgstr "" @@ -115,40 +115,40 @@ msgstr "" msgid "gtk-find" msgstr "" -#: portato/gui/templates/portato.glade:472 -msgid "<b>Installed, but not in portage anymore</b>" +#: portato/gui/templates/portato.glade:461 +msgid "Installed" msgstr "" -#: portato/gui/templates/portato.glade:551 -msgid "<span foreground='red'><b>MISSING KEYWORD</b></span>" +#: portato/gui/templates/portato.glade:474 portato/gui/gtk/windows.py:668 +#: portato/gui/gtk/windows.py:671 portato/gui/gtk/windows.py:674 +#: portato/gui/gtk/windows.py:773 portato/gui/gtk/windows.py:776 +#: portato/gui/gtk/windows.py:783 portato/gui/gtk/windows.py:787 +msgid "Masked" msgstr "" -#: portato/gui/templates/portato.glade:590 -msgid "Re_vert" +#: portato/gui/templates/portato.glade:488 portato/gui/gtk/windows.py:681 +#: portato/gui/gtk/windows.py:684 portato/gui/gtk/windows.py:745 +#: portato/gui/gtk/windows.py:750 +msgid "Testing" msgstr "" -#: portato/gui/templates/portato.glade:602 -msgid "E_build" +#: portato/gui/templates/portato.glade:535 +msgid "Re_vert" msgstr "" -#: portato/gui/templates/portato.glade:628 -msgid "Installed" +#: portato/gui/templates/portato.glade:547 +msgid "E_build" msgstr "" -#: portato/gui/templates/portato.glade:641 portato/gui/gtk/windows.py:667 -#: portato/gui/gtk/windows.py:670 portato/gui/gtk/windows.py:673 -#: portato/gui/gtk/windows.py:778 portato/gui/gtk/windows.py:781 -#: portato/gui/gtk/windows.py:788 portato/gui/gtk/windows.py:792 -msgid "Masked" +#: portato/gui/templates/portato.glade:568 +msgid "<span foreground='red'><b>MISSING KEYWORD</b></span>" msgstr "" -#: portato/gui/templates/portato.glade:655 portato/gui/gtk/windows.py:680 -#: portato/gui/gtk/windows.py:683 portato/gui/gtk/windows.py:750 -#: portato/gui/gtk/windows.py:755 -msgid "Testing" +#: portato/gui/templates/portato.glade:647 +msgid "<b>Installed, but not in portage anymore</b>" msgstr "" -#: portato/gui/templates/portato.glade:682 portato/gui/gtk/windows.py:127 +#: portato/gui/templates/portato.glade:682 portato/gui/gtk/windows.py:128 msgid "Package" msgstr "" @@ -156,11 +156,11 @@ msgstr "" msgid "_Remove" msgstr "" -#: portato/gui/templates/portato.glade:777 portato/gui/gtk/windows.py:1003 +#: portato/gui/templates/portato.glade:777 portato/gui/gtk/windows.py:998 msgid "Queue" msgstr "" -#: portato/gui/templates/portato.glade:805 portato/gui/gtk/windows.py:1100 +#: portato/gui/templates/portato.glade:805 portato/gui/gtk/windows.py:1095 msgid "Console" msgstr "" @@ -214,31 +214,19 @@ msgstr "" msgid "<b>Sync Options</b>" msgstr "" -#: portato/gui/templates/portato.glade:1164 -msgid "File name to use, if package.use is a directory: " -msgstr "" - -#: portato/gui/templates/portato.glade:1175 -msgid "Add only exact version to package.use" -msgstr "" - -#: portato/gui/templates/portato.glade:1188 -msgid "Add only exact version to package.keywords" -msgstr "" - -#: portato/gui/templates/portato.glade:1202 -msgid "File name to use, if package.keywords is a directory: " +#: portato/gui/templates/portato.glade:1154 +msgid "<u><i>Masking Keywords</i></u>" msgstr "" -#: portato/gui/templates/portato.glade:1236 -msgid "File name to use, if package.mask/package.unmask is a directory: " +#: portato/gui/templates/portato.glade:1169 +msgid "<u><i>Testing Keywords</i></u>" msgstr "" -#: portato/gui/templates/portato.glade:1247 -msgid "Add only exact version to package.mask/package.unmask" +#: portato/gui/templates/portato.glade:1184 +msgid "<u><i>Use-Flags</i></u>" msgstr "" -#: portato/gui/templates/portato.glade:1269 +#: portato/gui/templates/portato.glade:1206 msgid "" "<u>You may use the following placeholders:</u>\n" "\n" @@ -247,16 +235,28 @@ msgid "" "<i>$(cat-1)/$(cat-2)</i>: first/second part of the category" msgstr "" -#: portato/gui/templates/portato.glade:1295 -msgid "<u><i>Use-Flags</i></u>" +#: portato/gui/templates/portato.glade:1230 +msgid "Add only exact version to package.mask/package.unmask" msgstr "" -#: portato/gui/templates/portato.glade:1310 -msgid "<u><i>Testing Keywords</i></u>" +#: portato/gui/templates/portato.glade:1244 +msgid "File name to use, if package.mask/package.unmask is a directory: " msgstr "" -#: portato/gui/templates/portato.glade:1325 -msgid "<u><i>Masking Keywords</i></u>" +#: portato/gui/templates/portato.glade:1278 +msgid "File name to use, if package.keywords is a directory: " +msgstr "" + +#: portato/gui/templates/portato.glade:1289 +msgid "Add only exact version to package.keywords" +msgstr "" + +#: portato/gui/templates/portato.glade:1302 +msgid "Add only exact version to package.use" +msgstr "" + +#: portato/gui/templates/portato.glade:1316 +msgid "File name to use, if package.use is a directory: " msgstr "" #: portato/gui/templates/portato.glade:1342 @@ -342,98 +342,102 @@ msgstr "" msgid "Resume-loop called while process is still running!" msgstr "" -#: portato/plugins/etc_proposals.py:64 portato/plugins/etc_proposals.py:76 +#: portato/plugins/etc_proposals.py:65 portato/plugins/etc_proposals.py:77 msgid "Cannot start etc-proposals. No graphical frontend installed!" msgstr "" -#: portato/plugins/etc_proposals.py:78 +#: portato/plugins/etc_proposals.py:79 msgid "Cannot start etc-proposals. Not root!" msgstr "" -#: portato/gui/gtk/windows.py:72 +#: portato/plugins/notify.py:11 +msgid "Notify called while process is still running!" +msgstr "" + +#: portato/gui/gtk/windows.py:73 msgid "Plugin" msgstr "" -#: portato/gui/gtk/windows.py:75 +#: portato/gui/gtk/windows.py:76 msgid "Authors" msgstr "" -#: portato/gui/gtk/windows.py:80 portato/gui/gtk/windows.py:126 -#: portato/gui/gtk/windows.py:541 +#: portato/gui/gtk/windows.py:81 portato/gui/gtk/windows.py:127 +#: portato/gui/gtk/windows.py:542 msgid "Enabled" msgstr "" -#: portato/gui/gtk/windows.py:225 +#: portato/gui/gtk/windows.py:226 msgid "Results" msgstr "" -#: portato/gui/gtk/windows.py:494 +#: portato/gui/gtk/windows.py:495 msgid "<no description>" msgstr "" -#: portato/gui/gtk/windows.py:523 +#: portato/gui/gtk/windows.py:524 msgid "This is an expanded use flag and cannot be selected" msgstr "" -#: portato/gui/gtk/windows.py:542 +#: portato/gui/gtk/windows.py:543 msgid "Flag" msgstr "" -#: portato/gui/gtk/windows.py:543 +#: portato/gui/gtk/windows.py:544 msgid "Description" msgstr "" -#: portato/gui/gtk/windows.py:622 +#: portato/gui/gtk/windows.py:623 #, python-format msgid "Package could not be found: %s" msgstr "" -#: portato/gui/gtk/windows.py:693 +#: portato/gui/gtk/windows.py:694 msgid "Re_merge" msgstr "" -#: portato/gui/gtk/windows.py:890 +#: portato/gui/gtk/windows.py:885 msgid "Creating Database" msgstr "" -#: portato/gui/gtk/windows.py:895 +#: portato/gui/gtk/windows.py:890 msgid "Loading Config" msgstr "" -#: portato/gui/gtk/windows.py:906 +#: portato/gui/gtk/windows.py:901 msgid "Loading Plugins" msgstr "" -#: portato/gui/gtk/windows.py:919 +#: portato/gui/gtk/windows.py:914 msgid "Finishing startup" msgstr "" -#: portato/gui/gtk/windows.py:1006 +#: portato/gui/gtk/windows.py:1001 msgid "Options" msgstr "" -#: portato/gui/gtk/windows.py:1024 +#: portato/gui/gtk/windows.py:1019 msgid "Categories" msgstr "" -#: portato/gui/gtk/windows.py:1039 +#: portato/gui/gtk/windows.py:1034 msgid "Packages" msgstr "" -#: portato/gui/gtk/windows.py:1102 +#: portato/gui/gtk/windows.py:1097 #, python-format msgid "Console (%(title)s)" msgstr "" -#: portato/gui/gtk/windows.py:1154 +#: portato/gui/gtk/windows.py:1149 msgid "use flags" msgstr "" -#: portato/gui/gtk/windows.py:1161 +#: portato/gui/gtk/windows.py:1156 msgid "masking keywords" msgstr "" -#: portato/gui/gtk/__init__.py:20 +#: portato/gui/gtk/__init__.py:21 msgid "Loading Portage" msgstr "" @@ -571,90 +575,98 @@ msgstr "" msgid "Unrecognized line in configuration: %s" msgstr "" -#: portato/plugin.py:287 portato/plugin.py:293 portato/plugin.py:298 +#: portato/plugin.py:290 portato/plugin.py:296 portato/plugin.py:301 #, python-format msgid "%s cannot be imported." msgstr "" -#: portato/plugin.py:325 +#: portato/plugin.py:328 #, python-format msgid "Accessing hook '%(hook)s' of plugin '%(plugin)s' (before)." msgstr "" -#: portato/plugin.py:329 +#: portato/plugin.py:332 #, python-format msgid "Overriding hook '%(hook)s' with plugin '%(plugin)s'." msgstr "" -#: portato/plugin.py:336 +#: portato/plugin.py:339 #, python-format msgid "Accessing hook '%(hook)s' of plugin '%(plugin)s' (after)." msgstr "" -#: portato/plugin.py:356 +#: portato/plugin.py:359 #, python-format msgid "Loading plugin '%s' failed. Invalid XML syntax." msgstr "" -#: portato/plugin.py:359 +#: portato/plugin.py:362 #, python-format msgid "Loading plugin '%s' failed. Plugin does not comply with schema." msgstr "" -#: portato/plugin.py:388 +#: portato/plugin.py:391 #, python-format msgid "Plugin '%s' loaded." msgstr "" -#: portato/plugin.py:391 +#: portato/plugin.py:394 #, python-format msgid "Loading plugin '%(plugin)s' failed: Could not import %(import)s" msgstr "" -#: portato/plugin.py:456 +#: portato/plugin.py:459 #, python-format msgid "" "For hook '%(hook)s' an override is already defined by plugin '%(plugin)s'!" msgstr "" -#: portato.py:38 +#: portato/plistener.py:95 +msgid "Listener has not been started." +msgstr "" + +#: portato.py:40 msgid "runs pychecker (should only be used by developers)" msgstr "" -#: portato.py:41 +#: portato.py:43 #, python-format msgid "the frontend to use - possible values are: %s [default: %%default]" msgstr "" -#: portato.py:44 +#: portato.py:46 msgid "opens the ebuild viewer instead of launching Portato" msgstr "" -#: portato.py:47 +#: portato.py:49 msgid "validates the given plugin xml instead of launching Portato" msgstr "" -#: portato.py:60 +#: portato.py:52 +msgid "do not start listener" +msgstr "" + +#: portato.py:65 #, python-format msgid "Unknown frontend '%(frontend)s'. Correct frontends are: %(list)s" msgstr "" -#: portato.py:68 +#: portato.py:73 #, python-format msgid "" "'%(frontend)s' should be installed, but cannot be imported. This is " "definitly a bug. (%(error)s)" msgstr "" -#: portato.py:78 +#: portato.py:83 #, python-format msgid "Validation failed. XML syntax error: %s." msgstr "" -#: portato.py:81 +#: portato.py:86 msgid "Validation failed. Does not comply with schema." msgstr "" -#: portato.py:84 +#: portato.py:89 msgid "Validation succeeded." msgstr "" @@ -13,7 +13,7 @@ <xs:element name="hook" minOccurs="1" maxOccurs="unbounded"> <xs:complexType> <xs:sequence> - <xs:element name="connect" minOccurs="1" maxOccurs="unbounded"> + <xs:element name="connect" minOccurs="0" maxOccurs="unbounded"> <xs:complexType> <xs:simpleContent> <xs:extension base="xs:string"> diff --git a/plugins/noroot.xml b/plugins/notify.xml index 850a039..8de08c8 100644 --- a/plugins/noroot.xml +++ b/plugins/notify.xml @@ -1,12 +1,14 @@ <?xml version="1.0" encoding="UTF-8" ?> <plugin xmlns="http://portato.sourceforge.net/plugin" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://portato.sourceforge.net/plugin http://portato.sourceforge.net/plugin.xsd"> + <author>René 'Necoro' Neumann</author> - <name>No Root</name> - <import>portato.plugins.noroot</import> + <name>Notify</name> + <frontends>gtk</frontends> + + <import>portato.plugins.notify</import> <hooks> - <hook type = "am_i_root" call = "i_am_root"> - <connect type="override" /> - </hook> + <hook type = "after_emerge" call = "notify" /> </hooks> + </plugin> diff --git a/plugins/resume_loop.xml b/plugins/resume_loop.xml index 01dca78..124d61d 100644 --- a/plugins/resume_loop.xml +++ b/plugins/resume_loop.xml @@ -5,9 +5,7 @@ <import>portato.plugins.resume_loop</import> <hooks> - <hook type="emerge" call="set_data"> - <connect /> - </hook> + <hook type="emerge" call="set_data" /> <hook type="after_emerge" call="resume_loop"> <connect type="before">*</connect> 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) |