diff options
-rw-r--r-- | plugin.xsd | 87 | ||||
-rw-r--r-- | plugins/etc_proposals.py | 43 | ||||
-rw-r--r-- | plugins/etc_proposals.xml | 19 | ||||
-rw-r--r-- | plugins/gpytage.py | 27 | ||||
-rw-r--r-- | plugins/gpytage.xml | 13 | ||||
-rw-r--r-- | plugins/notify.py | 45 | ||||
-rw-r--r-- | plugins/notify.xml | 13 | ||||
-rwxr-xr-x | portato.py | 19 | ||||
-rw-r--r-- | portato/backend/portage/__init__.py | 12 | ||||
-rw-r--r-- | portato/backend/portage/package.py | 9 | ||||
-rw-r--r-- | portato/backend/portage/package_22.py (renamed from portato/plugins/gpytage.py) | 14 | ||||
-rw-r--r-- | portato/backend/portage/settings_22.py | 27 | ||||
-rw-r--r-- | portato/backend/portage/system.py | 13 | ||||
-rw-r--r-- | portato/backend/portage/system_22.py | 34 | ||||
-rw-r--r-- | portato/gui/dialogs.py | 7 | ||||
-rw-r--r-- | portato/gui/windows/mailinfo.py | 30 | ||||
-rw-r--r-- | portato/gui/windows/main.py | 19 | ||||
-rw-r--r-- | portato/gui/windows/plugin.py | 5 | ||||
-rw-r--r-- | portato/plugin.py | 636 | ||||
-rw-r--r-- | portato/plugins/__init__.py | 7 | ||||
-rw-r--r-- | portato/plugins/etc_proposals.py | 31 | ||||
-rw-r--r-- | portato/plugins/notify.py | 22 | ||||
-rw-r--r-- | setup.py | 5 |
23 files changed, 449 insertions, 688 deletions
diff --git a/plugin.xsd b/plugin.xsd deleted file mode 100644 index 985b105..0000000 --- a/plugin.xsd +++ /dev/null @@ -1,87 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://portato.sourceforge.net/plugin" targetNamespace="http://portato.sourceforge.net/plugin" elementFormDefault="qualified"> - <xs:element name="plugin"> - <xs:complexType> - <xs:all> - <xs:element name="name" type="string" /> - <xs:element name="author" type="string" /> - <xs:element name="import" type="importString" minOccurs="0"/> - <xs:element name="dependencies" minOccurs="0"> - <xs:complexType> - <xs:sequence> - <xs:element name="dependency" type="string" maxOccurs="unbounded" /> - </xs:sequence> - </xs:complexType> - </xs:element> - <xs:element name="hooks" minOccurs="0"> - <xs:complexType> - <xs:sequence> - <xs:element name="hook" minOccurs="1" maxOccurs="unbounded"> - <xs:complexType> - <xs:sequence> - <xs:element name="connect" minOccurs="0" maxOccurs="unbounded"> - <xs:complexType> - <xs:simpleContent> - <xs:extension base="xs:string"> - <xs:attribute name="type" default="before"> - <xs:simpleType> - <xs:restriction base="xs:string"> - <xs:enumeration value="before" /> - <xs:enumeration value="override" /> - <xs:enumeration value="after" /> - </xs:restriction> - </xs:simpleType> - </xs:attribute> - </xs:extension> - </xs:simpleContent> - </xs:complexType> - </xs:element> - </xs:sequence> - <xs:attribute name="type" type="string" use="required" /> - <xs:attribute name="call" type="functionCall" use="required" /> - </xs:complexType> - </xs:element> - </xs:sequence> - </xs:complexType> - </xs:element> - <xs:element name="options" minOccurs="0"> - <xs:complexType> - <xs:sequence> - <xs:element name="option" minOccurs="1" maxOccurs="unbounded" type="string" /> - </xs:sequence> - </xs:complexType> - </xs:element> - <xs:element name="menu" minOccurs="0"> - <xs:complexType> - <xs:sequence> - <xs:element name="item" minOccurs="1" maxOccurs="unbounded"> - <xs:complexType> - <xs:simpleContent> - <xs:extension base="string"> - <xs:attribute name="call" type="functionCall" use="required" /> - </xs:extension> - </xs:simpleContent> - </xs:complexType> - </xs:element> - </xs:sequence> - </xs:complexType> - </xs:element> - </xs:all> - </xs:complexType> - </xs:element> - <xs:simpleType name="importString"> - <xs:restriction base="xs:string"> - <xs:pattern value="([a-zA-Z_]+\.?)+" /> - </xs:restriction> - </xs:simpleType> - <xs:simpleType name="functionCall"> - <xs:restriction base="xs:string"> - <xs:pattern value="[a-zA-Z_][0-9a-zA-Z_]*" /> - </xs:restriction> - </xs:simpleType> - <xs:simpleType name="string"> - <xs:restriction base="xs:string"> - <xs:minLength value="1" /> - </xs:restriction> - </xs:simpleType> -</xs:schema> diff --git a/plugins/etc_proposals.py b/plugins/etc_proposals.py new file mode 100644 index 0000000..07f9a80 --- /dev/null +++ b/plugins/etc_proposals.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +# +# File: plugins/etc_proposals.py +# This file is part of the Portato-Project, a graphical portage-frontend. +# +# Copyright (C) 2007-2008 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> + +from portato.helper import error + +import os +from subprocess import Popen + +class EtcProposals (Plugin): + __author__ = "René 'Necoro' Neumann" + __description__ = "Adds support for <b>etc-proposals</b>, a graphical etc-update replacement." + __dependency__ = ["app-portage/etc-proposals"] + + def __init__ (self): + Plugin.__init__(self) + + self.prog = ["/usr/sbin/etc-proposals"] + self.add_call("after_emerge", self.hook, type = "after") + self.add_menu("Et_c-Proposals", self.menu) + + def launch (self, options = []): + if os.getuid() == 0: + Popen(self.prog+options) + else: + error("ETC_PROPOSALS :: %s",_("Cannot start etc-proposals. Not root!")) + + def hook (self, *args, **kwargs): + """Entry point for this plugin.""" + self.launch(["--fastexit"]) + + def menu (self, *args): + self.launch() + +register(EtcProposals) diff --git a/plugins/etc_proposals.xml b/plugins/etc_proposals.xml deleted file mode 100644 index 2caf341..0000000 --- a/plugins/etc_proposals.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?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>Etc-proposals</name> - - <import>portato.plugins.etc_proposals</import> - - <hooks> - <hook type = "after_emerge" call = "etc_prop"> - <connect type="after" /> - </hook> - </hooks> - - <menu> - <item call="etc_prop_menu">Et_c-Proposals</item> - </menu> - -</plugin> diff --git a/plugins/gpytage.py b/plugins/gpytage.py new file mode 100644 index 0000000..33509e1 --- /dev/null +++ b/plugins/gpytage.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# +# File: plugins/gpytage.py +# This file is part of the Portato-Project, a graphical portage-frontend. +# +# Copyright (C) 2008 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> + +from subprocess import Popen + +class GPytage (Plugin): + __author__ = "René 'Necoro' Neumann" + __description__ = "Adds a menu entry to directly start <b>gpytage</b>, a config editor." + __dependency__ = ["app-portage/gpytage"] + + def __init__ (self): + Plugin.__init__(self) + self.add_menu("Config _Editor", self.menu) + + def menu (self, *args): + Popen(["/usr/bin/gpytage"]) + +register(GPytage) diff --git a/plugins/gpytage.xml b/plugins/gpytage.xml deleted file mode 100644 index b203ae0..0000000 --- a/plugins/gpytage.xml +++ /dev/null @@ -1,13 +0,0 @@ -<?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>GPytage</name> - - <import>portato.plugins.gpytage</import> - - <menu> - <item call="gpytage">Config _Editor</item> - </menu> - -</plugin> diff --git a/plugins/notify.py b/plugins/notify.py new file mode 100644 index 0000000..bc1b2ea --- /dev/null +++ b/plugins/notify.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +# +# File: plugins/notify.py +# This file is part of the Portato-Project, a graphical portage-frontend. +# +# Copyright (C) 2007-2008 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 pynotify + +from portato import get_listener + +from portato.helper import warning, error, debug +from portato.constants import APP_ICON, APP + +class Notify (Plugin): + __author__ = "René 'Necoro' Neumann" + __description__ = "Show notifications when an emerge process finishes." + __dependency__ = ["dev-python/notify-python"] + + def __init__ (self): + Plugin.__init__(self) + self.add_call("after_emerge", self.notify) + + def notify (self, retcode, **kwargs): + if retcode is None: + warning("NOTIFY :: %s", _("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 + + get_listener().send_notify(base = text, descr = descr, icon = icon, urgency = urgency) + +register(Notify) diff --git a/plugins/notify.xml b/plugins/notify.xml deleted file mode 100644 index 9a89987..0000000 --- a/plugins/notify.xml +++ /dev/null @@ -1,13 +0,0 @@ -<?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>Notify</name> - - <import>portato.plugins.notify</import> - - <hooks> - <hook type = "after_emerge" call = "notify" /> - </hooks> - -</plugin> @@ -36,30 +36,13 @@ def main (): parser.add_option("--shm", action = "store", nargs = 3, type="long", dest = "shm", help = SUPPRESS_HELP) - parser.add_option("-x", "--validate", action = "store", dest = "validate", metavar="PLUGIN", - help = _("validates the given plugin xml instead of launching Portato")) - parser.add_option("-F", "--no-fork", "-L", action = "store_true", dest = "nofork", default = False, help = _("do not fork off as root") + (" (%s)" % _("-L is deprecated"))) # run parser (options, args) = parser.parse_args() - if options.validate: # validate a plugin - from lxml import etree - try: - etree.XMLSchema(file = XSD_LOCATION).assertValid(etree.parse(options.validate)) - except etree.XMLSyntaxError, e: - print _("Validation failed. XML syntax error: %s.") % e[0] - sys.exit(3) - except etree.DocumentInvalid: - print _("Validation failed. Does not comply with schema.") - sys.exit(3) - else: - print _("Validation succeeded.") - return - - elif options.nofork or os.getuid() == 0: # start GUI + if options.nofork or os.getuid() == 0: # start GUI from portato.gui import run from portato.helper import info info("%s v. %s", _("Starting Portato"), VERSION) diff --git a/portato/backend/portage/__init__.py b/portato/backend/portage/__init__.py index 6ccbf7f..be6cce6 100644 --- a/portato/backend/portage/__init__.py +++ b/portato/backend/portage/__init__.py @@ -12,5 +12,13 @@ from __future__ import absolute_import -from .system import PortageSystem -from .package import PortagePackage +from portage import VERSION as PV + +VERSION = tuple(map(int, (x.split("_")[0] for x in PV.split(".")))) + +if VERSION >= (2, 2): + from .system_22 import PortageSystem_22 as PortageSystem + from .package_22 import PortagePackage_22 as PortagePackage +else: + from .system import PortageSystem + from .package import PortagePackage diff --git a/portato/backend/portage/package.py b/portato/backend/portage/package.py index 3502306..78125ee 100644 --- a/portato/backend/portage/package.py +++ b/portato/backend/portage/package.py @@ -18,7 +18,12 @@ from .. import system from ..exceptions import BlockedException, PackageNotFoundException, DependencyCalcError from ...helper import debug, error, unique_array -import portage, portage_dep +import portage + +try: + import portage.dep as portage_dep +except ImportError: + import portage_dep import os.path @@ -221,7 +226,7 @@ class PortagePackage (Package): for dep in deps: if dep[0] == '!': # blocking sth - blocked = system.find_packages(dep, "installed", only_cpv = True) + blocked = system.find_packages(dep, "installed") if len(blocked) == 1: # only exact one match allowed to be harmless if blocked[0].get_slot_cp() == self.get_slot_cp(): # blocks in the same slot are harmless continue diff --git a/portato/plugins/gpytage.py b/portato/backend/portage/package_22.py index 22cc7ef..4fe03d9 100644 --- a/portato/plugins/gpytage.py +++ b/portato/backend/portage/package_22.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# File: portato/plugins/gpytage.py +# File: portato/backend/portage/package_22.py # This file is part of the Portato-Project, a graphical portage-frontend. # # Copyright (C) 2008 René 'Necoro' Neumann @@ -10,7 +10,13 @@ # # Written by René 'Necoro' Neumann <necoro@necoro.net> -from subprocess import Popen +from __future__ import absolute_import, with_statement -def gpytage(*args, **kwargs): - Popen(["/usr/bin/gpytage"]) +from .package import PortagePackage + +class PortagePackage_22 (PortagePackage): + """ + The 2.2 specialization of the portage package. + Currently this is identical to the normal one. + """ + pass diff --git a/portato/backend/portage/settings_22.py b/portato/backend/portage/settings_22.py new file mode 100644 index 0000000..a43d69e --- /dev/null +++ b/portato/backend/portage/settings_22.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# +# File: portato/backend/portage/settings_22.py +# This file is part of the Portato-Project, a graphical portage-frontend. +# +# Copyright (C) 2008 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> + +from __future__ import absolute_import + +import portage.sets +from .settings import PortageSettings + +class PortageSettings_22 (PortageSettings): + """Enhances the normal PortageSettings in ways, that it adds the setsconfig.""" + + def __init__ (self): + PortageSettings.__init__(self) + + def load (self): + PortageSettings.load(self) + + self.setsconfig = portage.sets.load_default_config(self.settings, self.trees[self.settings["ROOT"]]) diff --git a/portato/backend/portage/system.py b/portato/backend/portage/system.py index 0d81945..feaf4df 100644 --- a/portato/backend/portage/system.py +++ b/portato/backend/portage/system.py @@ -16,6 +16,7 @@ import re, os, os.path import portage from collections import defaultdict +from . import VERSION from .package import PortagePackage from .settings import PortageSettings from ..system_interface import SystemInterface @@ -36,8 +37,6 @@ class PortageSystem (SystemInterface): self.use_descs = {} self.local_use_descs = defaultdict(dict) - self._version = tuple([x.split("_")[0] for x in portage.VERSION.split(".")]) - def get_version (self): return "Portage %s" % portage.VERSION @@ -142,7 +141,7 @@ class PortageSystem (SystemInterface): """ if not only_cpv: - return [PortagePackage(x) for x in list_of_packages] + return [self.new_package(x) for x in list_of_packages] else: return list_of_packages @@ -154,7 +153,7 @@ class PortageSystem (SystemInterface): if only_cpv: return portage.best(list) else: - return PortagePackage(portage.best(list)) + return self.new_package(portage.best(list)) def find_best_match (self, search_key, masked = False, only_installed = False, only_cpv = False): t = [] @@ -166,7 +165,7 @@ class PortageSystem (SystemInterface): t = self.find_packages(search_key, pkgSet = pkgSet, masked = masked, with_version = True, only_cpv = True) - if self._version >= (2,1,5): + if VERSION >= (2,1,5): t += [pkg.get_cpv() for pkg in self.find_packages(search_key, "installed") if not (pkg.is_testing(True) or pkg.is_masked())] else: t = self.find_packages(search_key, "installed", only_cpv=True) @@ -287,7 +286,7 @@ class PortageSystem (SystemInterface): unresolved = [] for x in list: cpv = x.strip() - if len(cpv) and check(cpv): + if cpv and check(cpv): pkg = self.find_best_match(cpv, only_cpv = only_cpv) if pkg: resolved.append(pkg) @@ -304,7 +303,7 @@ class PortageSystem (SystemInterface): return portage.catpkgsplit(cpv) def sort_package_list(self, pkglist): - pkglist.sort(PortagePackage.compare_version) + pkglist.sort(PortagePackage.compare_version) # XXX: waaah ... direct package naming... =/ return pkglist def reload_settings (self): diff --git a/portato/backend/portage/system_22.py b/portato/backend/portage/system_22.py new file mode 100644 index 0000000..be27186 --- /dev/null +++ b/portato/backend/portage/system_22.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +# +# File: portato/backend/portage/system_22.py +# This file is part of the Portato-Project, a graphical portage-frontend. +# +# Copyright (C) 2008 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> + +from __future__ import absolute_import, with_statement + +import os +import portage + +from collections import defaultdict + +from .package_22 import PortagePackage_22 +from .settings_22 import PortageSettings_22 +from .system import PortageSystem + +class PortageSystem_22 (PortageSystem): + + def __init__ (self): + self.settings = PortageSettings_22() + portage.WORLD_FILE = os.path.join(self.settings.settings["ROOT"],portage.WORLD_FILE) + + self.use_descs = {} + self.local_use_descs = defaultdict(dict) + + def new_package (self, cpv): + return PortagePackage_22(cpv) diff --git a/portato/gui/dialogs.py b/portato/gui/dialogs.py index 8f0c78c..7f8a736 100644 --- a/portato/gui/dialogs.py +++ b/portato/gui/dialogs.py @@ -13,6 +13,13 @@ import gtk from ..helper import error +def mail_failure_dialog(e): + dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("Mail could not be sent")) + dialog.format_secondary_text(_("The error was: %s") % e) + ret = dialog.run() + dialog.destroy() + return ret + def queue_not_empty_dialog(): dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION, gtk.BUTTONS_NONE, _("There are some packages in the emerge queue and/or an emerge process is running.\nDo you really want to quit?")) #dialog.add_buttons(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_YES, gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE) diff --git a/portato/gui/windows/mailinfo.py b/portato/gui/windows/mailinfo.py index 8e476c6..1b5735a 100644 --- a/portato/gui/windows/mailinfo.py +++ b/portato/gui/windows/mailinfo.py @@ -12,11 +12,12 @@ from __future__ import absolute_import -import smtplib +import smtplib, socket import time from .basic import AbstractDialog from ..utils import GtkThread +from ..dialogs import mail_failure_dialog from ...helper import debug, info from ...constants import VERSION @@ -59,20 +60,23 @@ Subject: %s self.message = message def send (self): - debug("Connecting to server") - server = smtplib.SMTP("mail.necoro.eu") - debug("Sending mail") try: + debug("Connecting to server") + server = smtplib.SMTP("mail.necoro.eu") + debug("Sending mail") try: - server.sendmail(self.addr, self.TO, self.message) - except smtplib.SMTPRecipientsRefused, e: - info(_("An error occurred while sending. I think we where greylisted. The error: %s") % e) - info(_("Wait 60 seconds and try again.")) - time.sleep(60) - server.sendmail(self.addr, self.TO, self.message) - debug("Sent") - finally: - server.quit() + try: + server.sendmail(self.addr, self.TO, self.message) + except smtplib.SMTPRecipientsRefused, e: + info(_("An error occurred while sending. I think we where greylisted. The error: %s") % e) + info(_("Wait 60 seconds and try again.")) + time.sleep(60) + server.sendmail(self.addr, self.TO, self.message) + debug("Sent") + finally: + server.quit() + except socket.error, e: + mail_failure_dialog("%s (Code: %s)" % (e.args[1], e.args[0])) def cb_cancel_clicked (self, *args): diff --git a/portato/gui/windows/main.py b/portato/gui/windows/main.py index 364810d..b4e6353 100644 --- a/portato/gui/windows/main.py +++ b/portato/gui/windows/main.py @@ -607,13 +607,13 @@ class MainWindow (Window): # set plugins and plugin-menu splash(_("Loading Plugins")) - plugin.load_plugins("gtk") - menus = plugin.get_plugin_queue().get_plugin_menus() + plugin.load_plugins() + menus = [p.menus for p in plugin.get_plugin_queue().get_plugins()] if menus: self.tree.get_widget("pluginMenuItem").set_no_show_all(False) pluginMenu = self.tree.get_widget("pluginMenu") - for m in menus: + for m in itt.chain(*menus): item = gtk.MenuItem(m.label) item.connect("activate", m.call) pluginMenu.append(item) @@ -1082,13 +1082,8 @@ class MainWindow (Window): def save_plugin (p): def _save (): - stat_on = p.status >= p.STAT_ENABLED - hard_on = not p.get_option("disabled") - - if stat_on != hard_on: - return int(stat_on) - else: - return "" + return int(p.status >= p.STAT_ENABLED) + return _save # SESSION VERSION @@ -1553,8 +1548,8 @@ class MainWindow (Window): if queue is None: plugins = [] else: - plugins = queue.get_plugins() - + plugins = list(queue.get_plugins()) + PluginWindow(self.window, plugins) return True diff --git a/portato/gui/windows/plugin.py b/portato/gui/windows/plugin.py index 17c5326..9760658 100644 --- a/portato/gui/windows/plugin.py +++ b/portato/gui/windows/plugin.py @@ -15,6 +15,7 @@ from __future__ import absolute_import import gtk from .basic import AbstractDialog +from ...backend import system from ...helper import debug class PluginWindow (AbstractDialog): @@ -64,7 +65,7 @@ class PluginWindow (AbstractDialog): self.window.show_all() def build_dep_list (self): - store = gtk.TreeStore(gtk.gdk.Pixbuf, str) + store = gtk.ListStore(gtk.gdk.Pixbuf, str) self.depList.set_model(store) @@ -113,7 +114,7 @@ class PluginWindow (AbstractDialog): if not plugin.description: self.descrLabel.hide() else: - self.descrLabel.set_label(plugin.description) + self.descrLabel.set_markup(plugin.description) self.descrLabel.show() self.authorLabel.set_label(plugin.author) diff --git a/portato/plugin.py b/portato/plugin.py index cbadfd1..7b8a493 100644 --- a/portato/plugin.py +++ b/portato/plugin.py @@ -3,371 +3,183 @@ # File: portato/plugin.py # This file is part of the Portato-Project, a graphical portage-frontend. # -# Copyright (C) 2007 René 'Necoro' Neumann +# Copyright (C) 2008 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> -"""A module containing the management of the plugin system.""" - from __future__ import absolute_import -import os, os.path -from xml.dom.minidom import parse -from lxml import etree - -from .backend import system -from .constants import PLUGIN_DIR, XSD_LOCATION -from .helper import debug, info, warning, error, flatten +import os +import os.path as osp +from collections import defaultdict +from functools import wraps -class PluginImportException (ImportError): - pass +from .helper import debug, warning, info, error +from .constants import PLUGIN_DIR +from . import plugins as plugin_module -class UnmatchedDepsException (Exception): +class PluginLoadException (Exception): pass -class Options (object): - """The <options>-element.""" - - __options = ("disabled", "blocking") - - def __init__ (self, options = None): - - self.disabled = False - self.blocking = False - - if options: - self.parse(options) - - def parse (self, options): - for opt in options: - nodes = opt.childNodes - type = str(nodes[0].nodeValue.strip()) - if type in self.__options: - self.set(type, True) - - def get (self, name): - return self.__getattribute__(name) - - def set (self, name, value): - return self.__setattr__(name, value) - -class Menu: - """A single <menu>-element.""" - def __init__ (self, plugin, label, call): - """Constructor. - - @param plugin: the plugin this menu belongs to - @type plugin: Plugin - @param label: the label to show - @type label: string - @param call: the function to call relative to the import statement - @type call: string - - @raises PluginImportException: if the plugin's import could not be imported""" +class Menu (object): + __slots__ = ("label", "call") + def __init__ (self, label, call): self.label = label - self.plugin = plugin - - if self.plugin.needs_import(): # get import - imp = self.plugin.get_import() - try: - mod = __import__(imp, globals(), locals(), [call]) - except ImportError: - if self.plugin.unmatched_deps: - raise UnmatchedDepsException - else: - raise PluginImportException, imp - - try: - self.call = eval("mod."+call) # build function - except AttributeError: - raise PluginImportException, imp - else: - try: - self.call = eval(call) - except AttributeError: - raise PluginImportException, imp - -class Connect: - """A single <connect>-element.""" - - def __init__ (self, hook, type, depend_plugin): - """Constructor. - - @param hook: the parent Hook - @type hook: Hook - @param type: the type of the connect ("before", "after", "override") - @type type: string - @param depend_plugin: a plugin we are dependant on - @type depend_plugin: string or None""" - - self.type = type - self.hook = hook - self.depend_plugin = depend_plugin - - def is_before_type (self): - return self.type == "before" - - def is_after_type (self): - return self.type == "after" - - def is_override_type (self): - return self.type == "override" - -class Hook: - """A single <hook>-element.""" - - def __init__ (self, plugin, hook, call): - """Constructor. + self.call = call - @param plugin: the parent Plugin - @type plugin: Plugin - @param hook: the hook to add to - @type hook: string - @param call: the call to make - @type call: string""" +class Call (object): + __slots__ = ("plugin", "hook", "call", "type", "dep") + def __init__ (self, plugin, hook, call, type = "before", dep = None): self.plugin = plugin self.hook = hook self.call = call - self.connects = [] - - def parse_connects (self, connects): - """This gets a list of <connect>-elements and parses them. - - @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 == '': - type = "before" - - # get dep_plugin if available - dep_plugin = None - if c.hasChildNodes(): - nodes = c.childNodes - dep_plugin = nodes[0].nodeValue.strip() - - connect = Connect(self, type, dep_plugin) - self.connects.append(connect) - -class Plugin: - """A complete plugin.""" - - (STAT_DISABLED, STAT_TEMP_ENABLED, STAT_ENABLED, STAT_TEMP_DISABLED) = range(4) - - def __init__ (self, file, name, author): - """Constructor. - - @param file: the file name of the plugin.xml - @type file: string - @param name: the name of the plugin - @type name: Node - @param author: the author of the plugin - @type author: Node""" - - self.file = file - self.name = name.firstChild.nodeValue.strip() - self.author = author.firstChild.nodeValue.strip() - self.description = "" - self._import = None - self.hooks = [] - self.menus = [] - self.deps = [] - self.unmatched_deps = [] - self.options = Options() - |